Swift 中的枚举变量?
Enum variables in Swift?
我想以通用方式将多个值与一个枚举值相关联。
这可以在 Java 中完成:
enum Test {
A("test", 2);
final String var1;
final int var2;
Test (String var1, int var2) {
this.var1 = var1;
this.var2 = var2;
}
}
public static void main(String []args){
Test test = Test.A;
System.out.println(test.var1);
}
但是 Swift 好像不行?到目前为止,根据docs,有:
关联值。示例(来自 docs):
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
但这不是我需要的
原始值。示例(来自 docs):
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
这将是我需要的,但它只能有一个值!
是否有一个优雅的解决方案...?似乎是一种语言设计决策,因为它会与相关的价值观概念发生冲突,至少在当前形式下是这样。我知道我可以使用例如一本将枚举值映射到其余值的字典,但实际上缺少在一个安全步骤中执行此操作,例如 Java.
是的,这是一个设计决定,但在某些情况下您可以解决它。
这个想法是扩展一个类型以符合以下之一:
整数文字浮点文字字符串文字
可以在这里找到解决方案
Bryan Chen's solution:
How to create enum with raw type of CGPoint?
Sulthan 提供的第二种解决方案可能也是适合您的方法。
对于 Swift enum
,您只能使用 (String|Integer|Float)LiteralConvertible
类型作为原始值。如果您想使用现有类型(例如 CGPoint
)作为原始值,您应该遵循@Alex 的回答。
我将在这个答案中提供 2 个备选方案
非常简单的解决方案
enum Test: String {
case A = "foo:1"
case B = "bar:2"
var var1: String {
return split(self.rawValue, { [=10=] == ":" })[0]
}
var var2: Int {
return split(self.rawValue, { [=10=] == ":" })[1].toInt()!
}
}
let test = Test.A
println(test.var1) // -> "foo"
你不喜欢这个?转到下一个:)
使用 struct
和 static
常量的行为模拟
struct Test {
let var1: String
let var2: Int
private init(_ var1:String, _ var2:Int) {
self.var1 = var1
self.var2 = var2
}
}
extension Test {
static let A = Test("foo", 1)
static let B = Test("bar", 2)
static let allValues = [A, B]
}
let test = Test.A
println(test.var1) // -> "foo"
当然,struct
缺少 enum
的某些功能。你必须手动实现它。
Swift enum
隐式符合 Hashable
协议。
extension Test: Hashable {
var hashValue:Int {
return find(Test.allValues, self)!
}
}
func ==(lhs:Test, rhs:Test) -> Bool {
return lhs.var1 == rhs.var1 && lhs.var2 == rhs.var2
}
Test.A.hashValue // -> 0
Test.B.hashValue // -> 1
Test.A == Test.B // -> false
在第一个代码中,我们已经有allValues
对应Java中的values()
。 Java 中的 valueOf(...)
等同于 Swift 中的 RawRepresentable
协议中的 init?(rawValue:)
:
extension Test: RawRepresentable {
typealias RawValue = (String, Int)
init?(rawValue: RawValue) {
self.init(rawValue)
if find(Test.allValues, self) == nil{
return nil
}
}
var rawValue: RawValue {
return (var1, var2)
}
}
Test(rawValue: ("bar", 2)) == Test.B
Test(rawValue: ("bar", 4)) == nil
等等...
我知道这不是 "in a generic way"。我们永远无法效仿的一件事是 Swift 中的 "Matching Enumeration Values with a Switch Statement" 功能。你总是需要 default
个案例:
var test = Test.A
switch test {
case Test.A: println("is A")
case Test.B: println("is B")
default: fatalError("cannot be here!")
}
我对 Swift 的历史不够熟悉,无法知道在提出问题时这是否可能。但这就是我今天在 Swift 5.x:
中要做的
enum Direction {
case north
case east
case south
case west
func name() -> String {
switch self {
case .north: return "North"
case .east: return "East"
case .south: return "South"
case .west: return "West"
}
}
func degress() -> Double {
switch self {
case .north: return 0.0
case .east: return 90.0
case .south: return 180.0
case .west: return 270.0
}
}
}
它保留了 Swift enum
s 的所有优点,最重要的是,IMO,编译器在模式匹配时推断代码何时穷尽的能力。
我想以通用方式将多个值与一个枚举值相关联。
这可以在 Java 中完成:
enum Test {
A("test", 2);
final String var1;
final int var2;
Test (String var1, int var2) {
this.var1 = var1;
this.var2 = var2;
}
}
public static void main(String []args){
Test test = Test.A;
System.out.println(test.var1);
}
但是 Swift 好像不行?到目前为止,根据docs,有:
关联值。示例(来自 docs):
enum Barcode { case UPCA(Int, Int, Int, Int) case QRCode(String) }
但这不是我需要的
原始值。示例(来自 docs):
enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" case CarriageReturn = "\r" }
这将是我需要的,但它只能有一个值!
是否有一个优雅的解决方案...?似乎是一种语言设计决策,因为它会与相关的价值观概念发生冲突,至少在当前形式下是这样。我知道我可以使用例如一本将枚举值映射到其余值的字典,但实际上缺少在一个安全步骤中执行此操作,例如 Java.
是的,这是一个设计决定,但在某些情况下您可以解决它。 这个想法是扩展一个类型以符合以下之一: 整数文字浮点文字字符串文字
可以在这里找到解决方案 Bryan Chen's solution: How to create enum with raw type of CGPoint?
Sulthan 提供的第二种解决方案可能也是适合您的方法。
对于 Swift enum
,您只能使用 (String|Integer|Float)LiteralConvertible
类型作为原始值。如果您想使用现有类型(例如 CGPoint
)作为原始值,您应该遵循@Alex 的回答。
我将在这个答案中提供 2 个备选方案
非常简单的解决方案
enum Test: String {
case A = "foo:1"
case B = "bar:2"
var var1: String {
return split(self.rawValue, { [=10=] == ":" })[0]
}
var var2: Int {
return split(self.rawValue, { [=10=] == ":" })[1].toInt()!
}
}
let test = Test.A
println(test.var1) // -> "foo"
你不喜欢这个?转到下一个:)
使用 struct
和 static
常量的行为模拟
struct Test {
let var1: String
let var2: Int
private init(_ var1:String, _ var2:Int) {
self.var1 = var1
self.var2 = var2
}
}
extension Test {
static let A = Test("foo", 1)
static let B = Test("bar", 2)
static let allValues = [A, B]
}
let test = Test.A
println(test.var1) // -> "foo"
当然,struct
缺少 enum
的某些功能。你必须手动实现它。
Swift enum
隐式符合 Hashable
协议。
extension Test: Hashable {
var hashValue:Int {
return find(Test.allValues, self)!
}
}
func ==(lhs:Test, rhs:Test) -> Bool {
return lhs.var1 == rhs.var1 && lhs.var2 == rhs.var2
}
Test.A.hashValue // -> 0
Test.B.hashValue // -> 1
Test.A == Test.B // -> false
在第一个代码中,我们已经有allValues
对应Java中的values()
。 Java 中的 valueOf(...)
等同于 Swift 中的 RawRepresentable
协议中的 init?(rawValue:)
:
extension Test: RawRepresentable {
typealias RawValue = (String, Int)
init?(rawValue: RawValue) {
self.init(rawValue)
if find(Test.allValues, self) == nil{
return nil
}
}
var rawValue: RawValue {
return (var1, var2)
}
}
Test(rawValue: ("bar", 2)) == Test.B
Test(rawValue: ("bar", 4)) == nil
等等...
我知道这不是 "in a generic way"。我们永远无法效仿的一件事是 Swift 中的 "Matching Enumeration Values with a Switch Statement" 功能。你总是需要 default
个案例:
var test = Test.A
switch test {
case Test.A: println("is A")
case Test.B: println("is B")
default: fatalError("cannot be here!")
}
我对 Swift 的历史不够熟悉,无法知道在提出问题时这是否可能。但这就是我今天在 Swift 5.x:
中要做的enum Direction {
case north
case east
case south
case west
func name() -> String {
switch self {
case .north: return "North"
case .east: return "East"
case .south: return "South"
case .west: return "West"
}
}
func degress() -> Double {
switch self {
case .north: return 0.0
case .east: return 90.0
case .south: return 180.0
case .west: return 270.0
}
}
}
它保留了 Swift enum
s 的所有优点,最重要的是,IMO,编译器在模式匹配时推断代码何时穷尽的能力。