Swift: универсальная инициализация внутри неуниверсальной структуры - PullRequest
1 голос
/ 11 декабря 2019

Хорошо, я попытаюсь объяснить вам, что я пытаюсь получить на минимальном жизнеспособном примере: я хотел бы иметь такую ​​структуру:

struct MyStruct {
    let aBool: Bool
    let aInt: Int
    let aHashable: Hashable?
}

, но, конечно, это можетне может быть сделано, потому что:

Протокол 'Hashable' может использоваться только в качестве общего ограничения, потому что он имеет требования к Self или связанный тип

, и это нормально. Я могу получить то, что я хочу, следующим образом:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?
}

Но я хочу, чтобы моя структура имела два init следующим образом:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }

    init(aHashable: T?) {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init(aBool: Bool, aInt: Int, aHashable: T?) {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

И если я попытаюсь инициализировать структуру следующим образом:

let myStruct = MyStruct(aBool: true, aInt: 10)

Я получаю сообщение об ошибке:

Общий параметр 'T' не может быть выведен

Проблема в том, что даже если я повернуstruct в неуниверсальную структуру (с парой универсальных init):

struct MyStruct {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }

    init<T>(aHashable: T?) where T: Hashable {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init<T>(aBool: Bool, aInt: Int, aHashable: T?) where T: Hashable {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

Я все еще получаю ошибку. На этот раз для хранимого свойства let aHashable: T?:

Использование необъявленного типа 'T'

Какой правильный способ получить то, что я хочу? Спасибо.

1 Ответ

2 голосов
/ 11 декабря 2019

В этом случае вы хотите T Never, поскольку оно никогда не может иметь значения. Чтобы определить этот тип инициализации, вам нужно ограничить его таким расширением:

extension MyStruct where T == Never {
    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }
}

IMO, Swift также должен разрешить это как:

init(aBool: Bool, aInt: Int) where T == Never {...}

Но это в настоящее время не разрешеноSwift. Вы должны поместить это в расширение. Это просто проблема синтаксиса.

Для полноты, вот полный код:

struct MyStruct<T> where T: Hashable {
    let aBool: Bool
    let aInt: Int
    let aHashable: T?

    init(aHashable: T?) {
        self.init(aBool: false, aInt: 0, aHashable: aHashable)
    }

    private init(aBool: Bool, aInt: Int, aHashable: T?) {
        self.aBool = aBool
        self.aInt = aInt
        self.aHashable = aHashable
    }
}

extension MyStruct where T == Never {
    init(aBool: Bool, aInt: Int) {
        self.init(aBool: aBool, aInt: aInt, aHashable: nil)
    }
}

let myStruct = MyStruct(aBool: true, aInt: 10)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...