Advanced Java enums in Swift

2020-02-29 19:30发布

I have a number of Java classes I need to convert to Swift code. One of the classes has an advanced enum:

public enum Student {

  STUDENT_ONE("Steve", "Jobs")
  STUDENT_TWO("Tim", "Cook")

  private String _firstName;
  private String _lastName;
}

How can I replicate the same behavior in Swift?

5条回答
Root(大扎)
2楼-- · 2020-02-29 20:05

This is what I ended up doing - not sure about this at all:

struct Students {

    enum Students {
        case STUDENT_ONE(String, String)
        case STUDENT_TWO(String, String)
    }

    let STUDENT_ONE = Students.STUDENT_ONE("Steve", "Jobs")
    let STUDENT_TWO = Students.STUDENT_TWO("Steve", "Two")
}
查看更多
\"骚年 ilove
3楼-- · 2020-02-29 20:08

Moved here from another question marked as a duplicate so the variable names don't match up exactly, however, the concepts all do.

The most obvious way would be:

public enum EnumWeapon {
    case WOODEN_SWORD
    case STONE_SWORD
    case STEEL_SWORD

    func getName() -> String {
        switch self {
        case WOODEN_SWORD:  return "Wooden Sword"
        case STONE_SWORD:   return "Stone Sword"
        case STEEL_SWORD:   return "Steel Sword"
        }
    }

    func getDamage() -> Int {
        switch self {
        case WOODEN_SWORD:  return 4
        case STONE_SWORD:   return 6
        case STEEL_SWORD:   return 8
        }
    }
}

If you have a single value to associate with each enum case, you can use the raw value syntax, or just use it to simplify the enum case above:

public enum Weapon : Int {
    case WOODEN_SWORD = 4
    case STONE_SWORD = 6
    case STEEL_SWORD = 8

    func getDamage() -> Int {
        return rawValue
    }

    func getName() -> String {
        switch self {
        case .WOODEN_SWORD: return "Wooden Sword"
        case .STONE_SWORD:  return "Stone Sword"
        case .STEEL_SWORD:  return "Steel Sword"
        }
    }
}

Obviously, if you don't need the name, you can omit the getName function. Likewise you can omit the getDamage function and just use weapon.rawValue

An even simpler way, and yet more analogous to the actual Java implementation, would be to use a struct instead of an enum, as:

public struct Weapon {
    public let name : String
    public let damage : Int

    private init(name:String, damage:Int) {
        self.name = name
        self.damage = damage
    }

    public static let WOODEN_SWORD = Weapon(name: "Wooden Sword", damage: 4)
    public static let STONE_SWORD = Weapon(name: "Stone Sword", damage: 6)
    public static let STEEL_SWORD = Weapon(name: "Steel Sword", damage: 8)
}

and, be redefining operator ==, you can get equality comparisons:

func == (lhs:Weapon, rhs:Weapon) -> Bool {
    return lhs.name == rhs.name && lhs.damage == rhs.damage
}

and, by redefining operator ~= you can get switch to work as expected:

func ~= (lhs:Weapon, rhs:Weapon) -> Bool {
    return lhs == rhs
}

func test(sword:Weapon) {
    switch sword {
    case Weapon.STONE_SWORD:    print("stone")
    default:                    print("something else")
    }
}

test(Weapon.STONE_SWORD)

A whole lot of options, mostly it just depends on what you're really trying to do and how much data you need to wrap in the enum.

查看更多
Deceive 欺骗
4楼-- · 2020-02-29 20:18

I was trying to do the same thing with converting Java code to Swift, and ended up doing something like this :

public enum Student {

    case STUDENT_ONE
    case STUDENT_TWO

    var firstName: String {
        get {
            switch self {
            case .STUDENT_ONE:
                return "Steve"
            case .STUDENT_TWO:
                return "Tim"
            }
        }
    }

    var lastName: String {
        get {
            switch self {
            case .STUDENT_ONE:
                return "Jobs"
            case .STUDENT_TWO:
                return "Cook"
            }
        }
    }
}

Now, this is really long and messy and I'm not really sure whether this is the right way to do it, but I couldn't find anything else that worked. I would love to know if there is some other better way to do it.

查看更多
Rolldiameter
5楼-- · 2020-02-29 20:19

Enums are not necessarily the best choice to represent this type of data. I choose structs and this works well, using the correct accessors:

public struct Student {
    public let firstName : String
    public let lastName : String

    public static let STUDENT_ONE = Student(firstName: "Steve", lastName: "Jobs")
    public static let STUDENT_TWO = Student(firstName: "Tim", lastName: "Cook")
}
查看更多
Summer. ? 凉城
6楼-- · 2020-02-29 20:22

After some thought, I agree with godmoney that aksh1t's solution is better that my solution using Strings.

Anyway, here is a more concise variant of aksh1t's solution, using only one computed property returning a tuple: (tested in Swift 2.0)

enum Student {
    case STUDENT_ONE, STUDENT_TWO

    typealias Details = (firstName: String, lastName: String)
    var details : Details {
        switch(self) {
        case STUDENT_ONE : return ("Steve", "Jobs")
        case STUDENT_TWO : return ("Tim", "Cook")
        }
    }
}

// Usage:
func test(sd: Student.Details) {
    print(sd.firstName)
    print(sd.lastName)
}
test(Student.STUDENT_ONE.details)
查看更多
登录 后发表回答