swiftcastingtypecasting-operatortypecast-operator

Some duplicate enum type casting in Swift


See the codes below:

enum Gender {
  case Male, Female, Unknown
}
enum ExplicitGender {
  case Male, Female
}

func whatGender(_ g: Gender) {
  print("I am \(g)")
}

func makeSureYourGender() -> ExplicitGender {
  return ExplicitGender.Male
}

var myGender = makeSureYourGender();

// How to Cast type `ExplicitGender` to `Gender`?
// This fails
// whatGender(myGender)

The syntax myGender as ExplicitGender is not correct.

Actually, the Male,Female in ExplicitGender and Gender are the same. Make the 2 is 2 different Enum Types is not exactly correct.

Or There is another code structure or syntax to resolve this problem?

See also:


enum Language {
  case English, French, Arabic, Russian, Chinese, Spanish, Japanese, German, Italian
}

enum UNOfficialLanguage {
  case English, French, Arabic, Russian, Chinese, Spanish
}

In typescript, i will do it with:

type UNOfficialLanguage = 'English' | 'French' | 'Arabic' | 'Russian' | 'Chinese' | 'Spanish';
type Language = UNOfficialLanguage | 'Japanese' | 'German' | 'Italian';

Solution

  • Your TypeScript example is not an enum. It's a union of string literal types. There is no equivalent to literal types in Swift. (TypeScript also has enums, but they're a different thing.)

    Swift and TypeScript have radically different approaches to what it means to be a type. In TypeScript, two things that have the same structure are the same type ("structural typing"). In Swift, two things can have the same structure can be unrelated and what matters is the name of the type ("nominal typing"). The TS way is convenient, but there are many types it cannot express. The Swift way can express more things, but it lacks certain conveniences.

    For example, in TypeScript, if you declare two interfaces with the same properties, they are interchangeable:

    interface Animal {
      legs: number;
    }
    
    interface AirTravel {
      legs: number;
    }
    
    let trip: AirTravel = {legs: 4};
    
    function feedAnimal(a: Animal) {}
    
    feedAnimal(trip)  // No problem... legs are legs
    

    The equivalent code in Swift will give an error:

    struct Animal {
      var legs: Int
    }
    
    struct AirTravel {
      var legs: Int
    }
    
    let trip = AirTravel(legs: 4)
    
    func feedAnimal(_ a: Animal) {}
    
    feedAnimal(trip)
    // error: cannot convert value of type 'AirTravel' to expected argument type 'Animal'
    

    Whether you think one approach is better typically depends on the problems you're trying to solve. (I find the Swift approach dramatically more powerful than the TypeScript approach. Others find Swift restrictive because it won't let you do things you "know" are correct unless you can prove to the compiler it's correct.)

    To your example, just because two symbols have the same spelling (Language.English and UNOfficialLanguage.English) doesn't mean they are related in any way. If you want to convert between them, you'll need to convert between them.

    That said, Swift does have conveniences to convert to strings and from strings.

    enum Language: String {
      case english, french, arabic, russian, chinese, spanish, japanese, german, italian
    }
    
    enum UNOfficialLanguage: String {
      case english, french, arabic, russian, chinese, spanish
    }
    

    Note the addition of : String. This allows you to convert easily between the enum and a string representation of the enum.

    let l = UNOfficialLanguage.arabic
    let language = Language(rawValue: l.rawValue) // type is Language?
    

    Note that language is of type Language? since this conversion could fail. Since you happen to know that Language is a superset of UNOfficialLanguage, you could force the conversion in that direction:

    extension Language {
        init(_ official: UNOfficialLanguage) {
            self.init(rawValue: official.rawValue)!
        }
    }
    
    let language = Language(l) // type is Language
    

    For more on this feature, see Raw Values in the Swift Programming Language.