Advanced Java enums in Swift

后端 未结 5 952
萌比男神i
萌比男神i 2021-01-03 15:40

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\", \"J         


        
相关标签:
5条回答
  • 2021-01-03 16:15

    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")
    }
    
    0 讨论(0)
  • 2021-01-03 16:18

    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.

    0 讨论(0)
  • 2021-01-03 16:22

    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")
    }
    
    0 讨论(0)
  • 2021-01-03 16:30

    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)
    
    0 讨论(0)
  • 2021-01-03 16:32

    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.

    0 讨论(0)
提交回复
热议问题