gerbil
gerbil

Reputation: 923

Creating an enum instance

suppose I have

enum Example {
  case one(string: String)
  case two(string: String)
}

and now I have

let x = Example.one(string: "Hello")

The question:

let y = ?

how do I create another instance of the same enum in e, so that I end up with y == .one("World"))

Upvotes: 2

Views: 2533

Answers (2)

dfrib
dfrib

Reputation: 73236

The types of enum cases with associated values are closures with arguments corresponding to the type of the associated values, and with a return corresponding to the type of the enum (with the value of the return being the specific case). I.e., for your example above, the type of Example.one as well as Example.two is (String) -> Example, where the closures expressed by these two cases yield different results; instances of .one(...) and .two(...), respectively.

Hence, instead of writing your own method to "clone" a given case, you could simply have a computed property which returns the already existing closures Example.one and Example.two (if self is one or two, respectively), which can subsequently be invoked upon a String argument to construct a new Example instance (with value .one or .two; along with the supplied associated String value).

E.g.:

enum Example {
    case one(string: String) // type: (String) -> Example
    case two(string: String) // type: (String) -> Example

    var caseClosure: (String) -> Example {
        switch self {
        case .one: return Example.one
        case .two: return Example.two
        }
    }
}

let x = Example.one(string: "Hello") // .one("Hello")
let y = x.caseClosure("World")       // .one("World")

However, since all the cases in your example are closures of the same type, namely (String) -> Example (i.e. have the same number and type(s) of associated values), you might as well, as already proposed in a comment by @Hamish, wrap an enum with no associated values in a struct along with the always-String "associated value" a separate member of the struct. E.g. expanding Hamish's example with some initializers:

struct S {
    enum E {
        case one
        case two
    }
    var e: E
    var string: String // Since "associated value" is always the same type
    init(_ e: E, string: String) {
        self.e = e
        self.string = string
    }
    init(from s: S, string: String) {
        self.e = s.e
        self.string = string
    }
}

let x = S(.one, string: "Hello")
let y = S(from: x, string: "World")
let z = S(x.e, string: "World")

Upvotes: 1

naglerrr
naglerrr

Reputation: 2854

You do that by calling the Initializer exactly like you did for x:

enum Example {
    case one(string: String)
    case two(string: String)
}

let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")

let y = Example.one(string: "World")
print(y) // Prints one("World")

Also, The , in your enum declaration is wrong and has to be removed.


UPDATE:

The comment explained the question in more detail, so here is my updated answer:

An elegant way to solve this is to use a function on the original enum type Example.

enum Example {
    case one(string: String)
    case two(string: String)

    func cloneWith(string: String) -> Example {
        switch self {
        case .one:
            return .one(string: string)
        case .two:
            return .two(string: string)
        }
    }
}

let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")

let y = x.cloneWith(string: "World")
print(y) // Prints one("World")

Upvotes: 1

Related Questions