Swift: массив обобщенных типов с типами, соответствующими Equatable - PullRequest
0 голосов
/ 13 мая 2018

В 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' требует аргументов в <…>

… пока я пытался:

[File<Any>]

→ Тип 'Any' не соответствует протоколу 'Equatable'


[File<Any: Equatable>]

→ Последовательные объявления в строке должны быть разделены ';'


[File<Any, Equatable>]

→ Универсальный тип 'File' специализируется на слишком большом количестве параметров типа (получено 2, но ожидается 1)


[File<Any & Equatable>]

→ Использование 'Equatable' в качестве конкретного типа, соответствующего протоколу 'Equatable', не поддерживается


[File<(Any: Equatable)>]

→ Невозможно создать одноэлементный кортеж с меткой элемента


[File<(Any, Equatable)>]

→ Тип '(Any, Equatable)' не соответствует протоколу 'Equatable'`


[File<(Any & Equatable)>]

→ Использование 'Equatable' в качестве конкретного типа, соответствующего протоколу 'Equatable', не поддерживается


[File<[Any: Equatable]>]

→ «Файл» требует, чтобы «Equatable» соответствовал «Equatable»


[File<[Any, Equatable]>]

→ Последовательные объявления в строке должны быть разделены ';'


[File<[Any & Equatable]>]

→ «Файл» требует, чтобы «Equatable» соответствовал «Equatable»


Какой правильный синтаксис?


[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 голосов
/ 13 мая 2018

Вы должны указать тип параметра 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>]?
}

таким образом, вы можете считать строки, когда T равен Equatable

...