Можете ли вы форсировать дженерик c с двумя типами, чтобы гарантировать, что эти типы не идентичны? - PullRequest
3 голосов
/ 19 января 2020

Можно ли ограничить приведенный ниже шаблон c, чтобы гарантировать, что T1 и T2 не одного типа?

Вот что я пытаюсь сделать (но он не скомпилируется) ...

class Foo<T1, T2> where T1 != T2 {
}

С учетом этих типов ...

class A{}
class B{}
class SubA : A{}

Они должны быть действительными ...

let w = Foo<A, B>()
let x = Foo<B, A>()

Поскольку генерики Swift не выполняют стирание типов, Я считаю, что это также должно быть разрешено (но это нормально, если это не так. Это просто для «полноты» в обсуждении) ...

let y = Foo<A, SubA>

Это, однако, не должно быть разрешено ...

let y = Foo<A, A>

Теперь я могу поставить проверку в конструкторе, чтобы убедиться, что это так, но мне интересно, могу ли я сделать это во время компиляции с предложением 'where', но я не был успешно.

Использование Swift 5, если это важно.

1 Ответ

0 голосов
/ 21 января 2020

Здесь возможен подход с ошибками, генерируемыми во время компиляции для одних и тех же типов и переданными для разных типов.

Протестировано с: Xcode 11.2 / Swift 5.1.2

generics type checking to avoid same types

class A {}
class B {}

class Foo<T1, T2> {
    private init() {}
}

extension Foo where T1: A, T2: B {
    convenience init(_ a: T1, _ b: T2) {
        self.init()
    }
}

extension Foo where T1: B, T2: A {
    convenience init(_ b: T1, _ a: T2) {
        self.init()
    }
}

и тестирование ...

let test1 = Foo(A(), B())
let test2 = Foo(B(), A())
let test2 = Foo(A(), A()) // << Error: Ambiguous reference to initializer 'init(_:_:)'
let test2 = Foo(B(), B()) // << Error: Ambiguous reference to initializer 'init(_:_:)'
let test3 = Foo<String, String>() // Error: 'Foo<T1, T2>' initializer is inaccessible due to 'private' protection level

Обновление: для комментариев Роба Нейпира

enter image description here

...