【问题标题】:Swift Generics and enum as a data sourceSwift 泛型和枚举作为数据源
【发布时间】:2020-08-19 09:18:10
【问题描述】:

我有一个视图,它显示选项列表并为用户提供选择其中一个选项的选项。此视图必须可重用以与多组选项一起使用。我该怎么做。我尝试了下面的方法,但我收到了这个错误Protocol 'Options' can only be used as a generic constraint because it has Self or associated type requirements,我知道为什么会这样。有更好的方法吗?

protocol Options: CaseIterable {
    var displayName: String { get }
}

enum MyOptions: Options {
    case hello
    case mello
    case fello
    
    static var allCases: [MyOptions] {
        [.hello,.mello]
    }
    
    var displayName: String {
        "hello"
    }
}

/// This is just for testing

func testContains(option: Options, options: [Options]) -> Bool {
    true
}

print(testContains(option: MyOptions.fello, options: MyOptions.allCases))

【问题讨论】:

  • OptionSet 适合你吗?
  • 这些是不相关的选项集。不要认为 OptionSet 有意义
  • 我认为泛型不会帮助你。查看您对MyOptions 的声明,它本质上是在重新创建OptionSet。另一种方法是在枚举中使用字符串原始值
  • 例如:我会有不同类型的选项,例如 BaseOptions、ToppingOptions、PackagingOpitons,它们可以显示在同一个可重用视图中。选项集在这里如何帮助我
  • 可能不会。就在我看到您的代码时,您实际上是在重新创建OptionSet。您还没有准确显示您希望如何在视图中使用各种选项。你的协议需要的不仅仅是displayName

标签: swift swift-protocols


【解决方案1】:

您需要将您的 testContains 方法更改为具有类型约束的泛型 Options

func testContains<T: Options>(option: T, options: [T]) -> Bool {
    true
}

【讨论】:

  • 不只是这个功能,它在多个地方使用,比如30/40地方。你能想到的任何其他方法
  • @Kiran 那么你需要使所有这些函数通用。那有什么问题?另一种可能的解决方案是进行类型擦除,但这需要对您的代码进行更多更改。
  • 问题是我无法传递变量,为了做到这一点,我必须使我的视图通用,我的视图控制器通用以及许多其他通用的东西。例如:我想将当前选定选项的值存储在我的视图状态中,我不能这样做var selected option: Option 我必须使我的视图状态通用
  • 类型擦除对我们有什么帮助?
【解决方案2】:

只需将 CaseIterable 应用于需要它的枚举,而不是将其放在基础协议中。如果要求在基中包含 CaseIterable,那么 @Dávid Pásztor 是正确的,您必须使用类型擦除或泛型。

//
// used to be 'protocol Options: CaseIterable {'
//
protocol Options {
    var displayName: String { get }
}

// I just moved CaseIterable down from the base.
enum MyOptions: Options, CaseIterable {
    case hello
    case mello
    case fello

    static var allCases: [MyOptions] {
        [.hello,.mello]
    }

    var displayName: String {
        "hello"
    }
}

/// This now compiles and runs
func testContains(option: Options, options: [Options]) -> Bool {
    true
}

print(testContains(option: MyOptions.fello, options: MyOptions.allCases))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    相关资源
    最近更新 更多