Swift:类型符合Equatable的泛型数组

时间:2018-05-13 18:02:18

标签: swift generics types protocols equatable

在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
}

→参考通用类型&#39;文件&#39;需要&lt; ...&gt;

中的参数

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

[File<Any>]

→键入&#39;任何&#39;不符合协议&#39; Equatable&#39;

[File<Any: Equatable>]

→一行上的连续声明必须用&#39;;&#39;

分隔

[File<Any, Equatable>]

→通用类型&#39;文件&#39;专门有太多的类型参数(得到2,但预期1)

[File<Any & Equatable>]

→使用&#39; Equatable&#39;作为符合协议的具体类型&#39; Equatable&#39;不支持

[File<(Any: Equatable)>]

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

[File<(Any, Equatable)>]

→键入&#39;(Any,Equatable)&#39;不符合协议&#39; Equatable&#39;`

[File<(Any & Equatable)>]

→使用&#39; Equatable&#39;作为符合协议的具体类型&#39; Equatable&#39;不支持

[File<[Any: Equatable]>]

→&#39;文件&#39;要求“等于”#39;符合'Equatable&#39;

[File<[Any, Equatable]>]

→一行上的连续声明必须用&#39;;&#39;

分隔

[File<[Any & Equatable]>]

→&#39;文件&#39;要求“等于”#39;符合'Equatable&#39;

正确的语法是什么?

[EDIT]简化了示例

[编辑]更新示例:

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"

1 个答案:

答案 0 :(得分:1)

您必须在T上指定[File<T>]?参数的类型才能让编译器通过,请注意您在指定T后尝试创建同类数组作为最终类型,您无法在file上混合类型,即您无法混合File<Int>File<String>。如果您需要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

,您就可以计算行数