Использование связанного типа внутри протоколов и общих функций - PullRequest
0 голосов
/ 22 ноября 2018

Давайте предположим, что у меня protocol Foo с associatedtype Bar.Есть ли способ использовать этот же ассоциированный тип в качестве ограничения в универсальной функции внутри этого же протокола?

Для иллюстрации:

protocol Foo {
    associatedtype Bar
    func example<T: Bar>() -> T
}

Это выдаст Inheritance from non-protocol, non-class type 'Self.Bar'.Это имеет смысл, потому что во время компиляции мы не знаем, какой тип Bar будет .

Тем не менее, по какой-то причине, даже если я определю тип Bar, я будувсе равно получаю такую ​​же ошибку.Примерно так:

protocol Foo {
    associatedtype Bar: NSObject //OR: Protocol
    func example<T: Bar>() -> T //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar'
}

Оба этого и этого вопросов касаются одной и той же проблемы, но, по моему честному мнению, ни один из них не является реальным ответом.

Также, возможно, я подхожу к этому с неправильной точки зрения языка, но для визуализации моего варианта использования: мне нужно, чтобы, когда класс определял тип Bar, каждый T использовался в функции example(), должен иметь тип Bar, но зная, какой тип он вернет.Чтобы проиллюстрировать, что было бы моим уровнем техники:

protocol Foo {
    associatedtype Bar: NSObject //OR: Protocol
    //Compile Error: Inheritance from non-protocol, non-class type 'Self.Bar'
    func example<T: Bar>() -> T //OR: func example<T>() -> T where T: Bar
}

class ExampleBarType: NSObject { }

class ExampleObject: ExampleBarType { }

class FooImplementation: Foo {
    typealias Bar = ExampleBarType

    func example<T: Bar>() -> T { //OR: func example<T>() -> T where T: Bar {

    }
}

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

Ответы [ 3 ]

0 голосов
/ 22 ноября 2018

Я не уверен, что полностью понимаю ваш вариант использования, но разве этого недостаточно для выполнения того, что вам нужно сделать?

protocol Foo {
    associatedtype Bar
    func example() -> Bar
}

protocol BarProtocol { }

class BarOne: BarProtocol { }

class BarTwo: BarProtocol { }

class FooImplementationOne: Foo {
    func example() -> BarProtocol {
        return BarOne()
    }
}

class FooImplementationTwo: Foo {
    func example() -> BarProtocol {
        return BarTwo()
    }
}
0 голосов
/ 23 ноября 2018

То, что вы разрабатываете здесь, невозможно реализовать.Это не проблема Свифта;Я имею в виду, что это буквально невозможно реализовать, потому что типы не дают обещаний, которые вам нужны.Рассмотрим эту часть:

class ExampleBarType {} // Not an NSObject subclass.

class FooImplementation: Foo {
    typealias Bar = ExampleBarType

    func example<T: Bar>() -> T {
        // What would you write here?
    }
}

Как вы планируете написать тело этой функции?Рассмотрим следующую вызывающую сторону:

class MyBar: Bar {        
    init(x: Int) {}
}

let ex: MyBar = foo.example()

Как бы вы реализовали example?Как вы можете построить MyBar?Вы не знаете параметров для метода init (для этого требуется Int, которого у вас нет).Но ваша сигнатура функции утверждает, что эта функция будет возвращать любой конкретный подкласс Bar, который запрашивает вызывающая сторона.

В общем, вам следует избегать смешивания протоколов, обобщений и подклассов в одной системе типов.Они тянутся в разные стороны, и очень сложно поддерживать целостность вашей системы.Вы столкнетесь с множеством случаев, когда вы не сможете выполнить свои обещания.

Вы должны вернуться к своей конкретной проблеме и необходимости.Если вы делаете это «потому что я хочу быть как можно более универсальным», я рекомендую остановиться.Система типов Swift очень мощная, но также имеет некоторые очень хитрые ограничения и «настолько универсальна, насколько это возможно только потому, что» почти всегда врезается в эти ограничения.Однако если у вас есть конкретный вариант использования в реальной программе, вы часто (хотя и не всегда) можете избежать этих головных болей.

0 голосов
/ 22 ноября 2018

Я знаю, что это сложная тема.Пусть этот путь может дать вам немного света.

protocol Foo {
associatedtype Bar: NSObject //OR: Protocol
func example() -> Bar  //OR:
}

class ExampleBarType: NSObject { }

class ExampleObject: ExampleBarType { }

class FooImplementation: Foo {
typealias Bar = ExampleBarType
func example<T: Bar>() -> T {
    return Bar.init() as! T
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...