【问题标题】:How to declare enums in Swift of a particular class type?如何在 Swift 中声明特定类类型的枚举?
【发布时间】:2017-08-04 09:09:03
【问题描述】:

我正在尝试创建一个类并将该类用作我的新枚举的类型,如下所示。

class Abc{
    var age  = 25
    var name = "Abhi"
}

enum TestEnum : Abc {
    case firstCase
    case secondCase
}

我在操场上遇到以下错误。

error: raw type 'Abc' is not expressible by any literal

所以我尝试像这样遵循 RawRepresentable 协议。

extension TestEnum : RawRepresentable{
    typealias RawValue = Abc

    init?(rawValue:RawValue ) {
        switch rawValue {
        case Abc.age :
            self = .firstCase

        case Abc.name :
            self = .secondCase
        }
    }

    var rawValue : RawValue {
        switch self{

        case .firstCase :
            return Abc.age

        case .secondCase :
            return Abc.name
        }
    }
}

在此之后我收到以下错误:

error: raw type 'Abc' is not expressible by any literal
error: instance member 'age' cannot be used on type 'Abc'
error: instance member 'name' cannot be used on type 'Abc'

声明某种类类型的枚举的正确方法是什么,对此并不清楚。有人帮忙吗?

【问题讨论】:

  • enum 是值类型而class 是引用类型,所以我认为不可能。
  • 你想要达到什么目的?
  • 来自文档:“原始值可以是字符串、字符或任何整数或浮点数类型”
  • @MartinR,您可以使用自定义类型作为原始值。看我的回答。
  • 就像任何其他预定义类型一样,我想要一个我自己类型的枚举。类类型。

标签: swift enums


【解决方案1】:

我不太确定您想要实现什么,但请看一下我在项目中使用的实现和方法:

class Abc {
    var age: Int
    var name: String

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


enum TestEnum {
    case firstCase
    case secondCase

    var instance: Abc {
        switch self {
        case .firstCase: return Abc(age: 25, name: "John")
        case .secondCase: return Abc(age: 20, name: "Marry")
        }
    }
}

//Usage:

let abc = TestEnum.secondCase.instance
print(abc.age) //prints '20'

【讨论】:

  • 我们可以像这样声明枚举, enum SomeEnum : Int{ } 或 enum SomeEnum : String{ } 。为什么不喜欢这个枚举 SomeEnum : SomeClass{ } ?
  • 回答 iPhoneDeveloper 的问题:因为枚举的每个 case 本质上都必须归结为 String 或 Int。 Mohamemed 上面的回答解释了一种复杂的方式来进行声明,就像你说的那样,并且仍然让枚举的每个案例都符合这些规则。但是,为了代码的可读性,我更喜欢 Michal 的回答。它有效。
  • 好东西。
  • 每次都会生成不同的Abc实例。
【解决方案2】:

来自文档

特别是,原始值类型必须符合 Equatable 协议和以下协议之一: ExpressibleByIntegerLiteral 用于整数文字, ExpressibleByFloatLiteral 用于浮点文字, ExpressibleByStringLiteral 用于包含任意数字的字符串文字 字符数,以及 ExpressibleByUnicodeScalarLiteral 或 ExpressibleByExtendedGraphemeClusterLiteral 用于字符串文字 只包含一个字符。

因此,让您的类 Abc 符合 Equatable 和上述协议之一。这是一个例子

public class Abc : Equatable,ExpressibleByStringLiteral{
    var age  = 25
    var name = "Abhi"
    public static func == (lhs: Abc, rhs: Abc) -> Bool {
        return (lhs.age == rhs.age && lhs.name == rhs.name)
    }
    public required init(stringLiteral value: String) {
        let components = value.components(separatedBy: ",")
        if components.count == 2 {
            self.name = components[0]
            if let age = Int(components[1]) {
                self.age = age
            }
        }
    }
    public required convenience init(unicodeScalarLiteral value: String) {
        self.init(stringLiteral: value)
    }
    public required convenience init(extendedGraphemeClusterLiteral value: String) {
        self.init(stringLiteral: value)
    }
}

enum TestEnum : Abc {
    case firstCase = "Jack,29"
    case secondCase = "Jill,26"
}

现在你可以像

一样初始化你的枚举了
let exEnum = TestEnum.firstCase
print(exEnum.rawValue.name) // prints Jack

有关详细讨论和示例,您可以参考 https://swiftwithsadiq.wordpress.com/2017/08/21/custom-types-as-raw-value-for-enum-in-swift/

【讨论】:

  • 我如何从枚举中获取名称?
  • 你为什么使用这个功能“==”?目的是什么?你怎么称呼它?
  • 这用于符合 Equatable 协议。这是将类用作原始值的要求之一。
  • 要使一个类相等,你需要为它声明 operator == 。由于该类将用作原始值,因此系统必须知道哪些情况将被视为相等。在这种情况下,两个具有相同名称和相同年龄的原始值的情况将被视为相等,尽管它们可能属于不同的实例。
  • 你失去了类型检查和代码完成,因为你使用字符串文字创建了一个包含一堆代码的类,只是为了像枚举这样简单的事情:),很快我们就回到过去了哈哈
【解决方案3】:

看看Associated Values。 以您为例:

class Abc {
    var age  = 25
    var name = "Abhi"
}

enum TestEnum {
    case age(Int)
    case name(String)
}

那么你可以这样使用它:

var person = Abc()
...
var value = TestEnum.age(person.age)

switch value {
    case .age(let age):
        print("Age: \(age).")
    case .name(let name):
        print("Name: \(name).")
}

为方便起见,您可以为枚举编写扩展名,这将获取您的 Abc 对象并将其转换为枚举值:

static func fromAbc(_ object: Abc) -> TestEnum? {
    if object.age {
        return TestEnum.age(object.age)
    }

    if object.name {
        return TestEnum.name(object.name)
    }

    return nil
}

注意:在func fromAbc(object: Abc) -> TestEnum? 中,您应该将 if 中的条件替换为可以表示为 Bool(age > 0 等)的内容。

至于行值 - 在doc 中声明

原始值可以是字符串、字符或任何整数或浮点数类型。每个原始值在其枚举声明中必须是唯一的。

我不确定你是否适合在那里上课。

【讨论】:

  • 你可以。看我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多