Swift 中的某些重复枚举类型转换

Some duplicate enum type casting in Swift

查看以下代码:

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)

语法 myGender as ExplicitGender 不正确。

其实Male,FemaleExplicitGenderGender中是一样的。 使 2 is 2 different Enum Types 不完全正确。

或者有另一种代码结构或语法来解决这个问题?

另请参阅:


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

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

typescript 中,我将使用:

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

您不能(向下转换或向上转换)转换彼此不相关的对象。请查看 casting on swift 以获取有关如何投射的信息。

Gender 和 ExplicitGender 是互不相关的枚举。

一种解决方案是创建一个辅助函数,将 Gender 类型转换为 ExplicitGender 类型,反之亦然。请以下面的代码为例:

func genderFromExplicitGender(gender: ExplicitGender) -> Gender {
  switch gender {
   case .Male: return .Male
   case .Female: return .Female
 }
return .Unknown }

这里要注意的是,即使性别和明确性别有男性和女性。无论如何,它们彼此没有关系。上面的代码检查了男性(如 ExplicitGender.Male)和 returns 男性(如 Gender.Male),对女性也是如此。

我会建议您在 swift

中阅读更多关于铸造的内容

您的 TypeScript 示例不是枚举。它是字符串文字类型的联合。 Swift 中没有等同于文字类型的东西。 (TypeScript 也有枚举,但它们是不同的东西。)

Swift 和 TypeScript 对于类型的含义有着截然不同的方法。在 TypeScript 中,具有相同结构的两个事物是相同的类型(“结构类型”)。在 Swift 中,两个可以具有相同结构的事物可以是无关的,重要的是类型的名称(“名义类型”)。 TS方式方便,但是有很多类型它不能表达。 Swift方式可以表达更多的东西,但是缺少了一定的便利。

例如,在 TypeScript 中,如果您声明两个具有相同属性的接口,它们是可以互换的:

interface Animal {
  legs: number;
}

interface AirTravel {
  legs: number;
}

let trip: AirTravel = {legs: 4};

function feedAnimal(a: Animal) {}

feedAnimal(trip)  // No problem... legs are legs

Swift中的等效代码会报错:

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'

您是否认为一种方法更好通常取决于您要解决的问题。 (我发现 Swift 方法比 TypeScript 方法强大得多。其他人发现 Swift 有限制,因为它不会让你做你“知道”是正确的事情,除非你能向编译器证明它是正确的.)

对于您的示例,仅仅因为两个符号具有相同的拼写(Language.EnglishUNOfficialLanguage.English)并不意味着它们有任何关联。如果要在它们之间进行转换,则需要在它们之间进行转换。

也就是说,Swift 确实可以方便地转换为字符串和从字符串转换。

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

enum UNOfficialLanguage: String {
  case english, french, arabic, russian, chinese, spanish
}

注意添加 : String。这使您可以轻松地在枚举和枚举的字符串表示之间进行转换。

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

请注意 languageLanguage? 类型,因为此转换可能会失败。由于您碰巧知道 Language 是 UNOfficialLanguage 的超集,因此您可以强制朝那个方向进行转换:

extension Language {
    init(_ official: UNOfficialLanguage) {
        self.init(rawValue: official.rawValue)!
    }
}

let language = Language(l) // type is Language

有关此功能的更多信息,请参阅 Swift 编程语言中的 Raw Values