【问题标题】:Swift enum inheritanceSwift枚举继承
【发布时间】:2016-01-16 10:47:01
【问题描述】:

你能在 Swift 中继承枚举吗?关于枚举继承应该注意哪些规则?

如下测试代码:

enum TemperatureUnit: Int {
    case Kelvin, Celcius, Farenheit
}

enum TemperatureSubunit : Temperature {  
}

生成

error: type 'TemperatureSubunit' does not conform to protocol 'RawRepresentable'

【问题讨论】:

    标签: ios swift inheritance enums rawrepresentable


    【解决方案1】:

    看我的例子,简单多了:Can an enum contain another enum values in Swift?

    详情

    测试日期:

    • Xcode 9.2、Swift 4 和 3
    • Xcode 10.2 (10E125) 和 11.0 (11A420a),Swift 5

    解决方案

    enum State {
        case started
        case succeeded
        case failed
    }
    
    enum ActionState {
        case state(value: State)
        case cancelled
    }
    

    结果

    ActionState 枚举有 4 个值:

    .state(value: .started)
    .state(value: .succeeded)
    .state(value: .failed)
    .cancelled
    

    另一个样本

    import Foundation
    
    enum StringCharactersTransformType {
        case upperCase
        case lowerCase
    }
    
    enum StringTransformType {
        case state(value: StringCharactersTransformType)
        case normal
    
        static var upperCase: StringTransformType {
            return .state(value: .upperCase)
        }
    
        static var lowerCase: StringTransformType {
            return .state(value: .lowerCase)
        }
    }
    
    var type = StringTransformType.normal
    print(type)
    type = .upperCase
    print(type)
    type = .lowerCase
    print(type)
    

    结果

    【讨论】:

    • 我喜欢。但是 Enum 的想法是你可以推断出常量。比如:someFunction("hello world",.upperCase)someFunction("hello world",.lowerCase) 等等。这个:someFunction("hello world",.state(.upperCase))不是很可读吗?好主意。
    • 是的,你是对的。我已经编辑了答案(添加了漂亮代码的示例)。这样更好吗?
    • 虽然是一种反向继承。这更像是组合。如果你考虑一下。在我看来,枚举在面向协议的编程中工作得很好,而在 OOP 和继承中则不然。幸运的是 swift 仍然支持 OOP 和 POP。现在。
    • 好主意!枚举组合!
    • 是的,它实际上解决了无法扩展来自 3rd 方框架的错误枚举的问题。构图正是我所需要的!
    【解决方案2】:

    在 Swift 语言中,我们有结构体、枚举和类。结构和枚举通过复制传递,但类通过引用传递。只有类支持继承,枚举和结构不支持。

    所以要回答您的问题,您不能使用 Enum(和 Struct 类型)进行继承。看看这里:

    stackOverflow difference classes vs structs

    【讨论】:

    • 惊人的失败,但就这样吧。感谢您提供信息。
    【解决方案3】:

    正如 Korpel 已经回答的那样,目前 Enums 不支持实际继承。所以不可能让某个 Enum 扩展并继承另一个 enum 的情况。

    但是,我要补充一点,Enums 确实支持协议,再加上 Swift 2 中引入的协议扩展和新的面向协议的编程方法(参见this video),可以实现类似于继承的东西.这是我经常使用的一种技术,用于定义由枚举驱动的UITableViewController:s,指定表的部分以及每个部分中的行,并添加一些有用的行为。例如,请参见以下示例代码:

    import UIKit
    
    protocol TableSection {
        static var rows: [Self] { get }
    
        var title: String { get }
    
        var mandatoryField: Bool { get }
    }
    
    extension TableSection {
        var mandatoryTitle: String {
            if mandatoryField {
                return "\(title)*"
            } else {
                return title
            }
        }
    }
    
    enum RegisterTableSection: Int, TableSection {
        case Username
        case Birthdate
        case Password
        case RepeatPassword
    
        static var rows: [RegisterTableSection] {
            return [.Username, .Password, .RepeatPassword]
        }
    
        var title: String {
            switch self {
            case .Username:
                return "Username"
            case .Birthdate:
                return "Date of birth"
            case .Password:
                return "Password"
            case .RepeatPassword:
                return "Repeat password"
            }
        }
    
        var mandatoryField: Bool {
            switch self {
            case .Username:
                return true
            case .Birthdate:
                return false
            case .Password:
                return true
            case .RepeatPassword:
                return true
            }
        }
    }
    
    class ViewController: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return RegisterTableSection.rows.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            guard let row = RegisterTableSection(rawValue: indexPath.row) else {
                // This should never happen
                return UITableViewCell()
            }
    
            let cell = UITableViewCell()
            cell.textLabel?.text = row.mandatoryTitle
            return cell
    
        }
    }
    

    前面的代码会呈现下表:

    注意通过实现协议,我们的RegisterTableSection 枚举必须为协议中定义的方法和变量提供实现。最有趣的是,它通过TableSection 协议扩展继承变量mandatoryTitle 的默认实现

    我已经上传了这个例子的源代码here

    【讨论】:

    • 这是一个很好的答案,展示了面向协议编程的另一个好处
    • 路易斯的好答案!
    猜你喜欢
    • 2010-10-19
    • 2012-04-04
    • 2011-03-07
    • 1970-01-01
    相关资源
    最近更新 更多