【问题标题】:Swift: array of generics with types conforming EquatableSwift:类型符合 Equatable 的泛型数组
【发布时间】:2018-10-23 10:47:55
【问题描述】:

在 Swift 中,如何定义类型符合 Equatable 的泛型数组?

例子:

struct File<T: Equatable> {
    public var lines: [T]
    private var lineCursor = 0
    public var currentLine: T {
        get { return lines[lineCursor] }
        set { lineCursor = lines.index(where: { $0 == newValue }) ?? 0 }
    }
}

struct Folder {
    public var files: [File]? // compile time error
}

→ 对泛型“文件”的引用需要

中的参数

……到目前为止我试过了:

[File&lt;Any&gt;]

→ 类型 'Any' 不符合协议 'Equatable'


[File&lt;Any: Equatable&gt;]

→ 一行上的连续声明必须用';'分隔


[File&lt;Any, Equatable&gt;]

→ 泛型类型“文件”专用于太多类型参数(有 2 个,但预期为 1 个)


[File&lt;Any &amp; Equatable&gt;]

→ 不支持使用 'Equatable' 作为符合协议 'Equatable' 的具体类型


[File&lt;(Any: Equatable)&gt;]

→ 无法创建带有元素标签的单元素元组


[File&lt;(Any, Equatable)&gt;]

→ 类型'(Any, Equatable)' 不符合协议'Equatable'`


[File&lt;(Any &amp; Equatable)&gt;]

→ 不支持使用 'Equatable' 作为符合协议 'Equatable' 的具体类型


[File&lt;[Any: Equatable]&gt;]

→ 'File' 要求 'Equatable' 符合 'Equatable'


[File&lt;[Any, Equatable]&gt;]

→ 一行上的连续声明必须用';'分隔


[File&lt;[Any &amp; Equatable]&gt;]

→ 'File' 要求 'Equatable' 符合 'Equatable'


正确的语法是什么?


[编辑] 简化示例


[编辑] 更新示例:

class File<T: Equatable> {
    var lines = [T]()
    var lineCursor: Int = 0
    var currentLine: T {
        get { return lines[lineCursor] }
        set { lineCursor = lines.index(where: { $0 == newValue }) ?? 0 }
    }
    var visible = true
}

class Folder {
    var files = [File]() // Generic parameter 'Type' could not be inferred; I want this to be a mixed array
    func currentLinesFromVisibleFiles() -> String {
        return files.filter({ $0.visible }).map({ String(describing: $0.currentLine) }).joined(separator: "/")
    }
}

var stringFile = File<String>()
stringFile.lines = ["strong", "string", "a", "b", "c"]
stringFile.currentLine = "string"
stringFile.visible = true

var intFile = File<Int>()
intFile.lines = [6, 12, 0, 489]
intFile.currentLine = 489
intFile.visible = true

var doubleFile = File<Double>()
doubleFile.lines = [92.12, 4.9753, 1.6]
doubleFile.currentLine = 92.12
doubleFile.visible = false

var boolFile = File<Bool>()
boolFile.lines = [true, false]
boolFile.currentLine = true
boolFile.visible = true

var folder = Folder()
folder.files = [stringFile, intFile, doubleFile, boolFile]

let output = folder.currentLinesFromVisibleFiles() // I want: "string/489/true"

【问题讨论】:

  • 您希望在 DataFile 类中使用什么类型的值? String? Int?那是你需要使用的,而不是Any
  • Data 类型的意义何在?我真的看不出用非受限泛型类型定义具有单个实例属性的类型有什么意义。为什么不在File 类型中简单地使用public var lines: [Type]?此外,复制现有的内置类型名称是一个坏主意,因为它很可能会导致代码读者混淆。
  • @rmaddy:我想使用任何可用或将可用的类型。像 FloatBool 以及任何未来的 Equatable 自定义类型。
  • 很好,但是当您实例化 FileData 时,您需要使用特定(和 Equatable)类型。 Any 不是 Equatable
  • @DávidPásztor:感谢您的评论。该代码只是帮助理解我想学习的内容的示例。我猜“复制现有的内置类型名称”是指Type

标签: swift generics types protocols equatable


【解决方案1】:

您必须在[File&lt;T&gt;]? 上指定T 参数的类型才能让编译器通过,请注意,您正在尝试创建一个同构数组,一旦您将T 指定为最终类型,您就不能在file 上混合类型,即不能混合File&lt;Int&gt;File&lt;String&gt;。如果您需要Equatable 一致性来计算currentLine,您可以使用条件一致性来动态添加属性,或者T 不相等,如:

protocol HasCurrentLine{
    associatedtype LineType
    var currentLine: LineType { set get }
}

struct File<T> where T:Any {
    public var lines: [T]
    var lineCursor = 0
}

extension File : HasCurrentLine where T : Equatable{
    typealias LineType = T
    var currentLine: T {
        get { return lines[lineCursor] }
        set { lineCursor = lines.index(where: { $0 == newValue }) ?? 0 
    }
  }
}
struct Folder {
    public var files: [File<Any>]?
}

这样您就可以在TEquatable 时计算行数

【讨论】:

  • 非常感谢您的回答。按照这个示例,我在尝试将 File() 保存到 files 数组时遇到了问题:Cannot convert value of type 'File&lt;Int&gt;' to expected element type 'File&lt;Any&gt;'。我更新了问题中的示例以减少误解。
猜你喜欢
  • 1970-01-01
  • 2014-12-09
  • 2022-08-02
  • 2020-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多