Внедрение зависимостей со связанными типами, вызывающими аргументы без имен типов (undescores) в Swift - PullRequest
1 голос
/ 10 июля 2019

Ситуация следующая: я использую протокол для внедрения зависимостей, и лучший способ реализовать это в Swift - использовать ключевое слово associatedtype.Я также использую состав протокола, так как некоторые реализации TestProtocol нуждаются в более чем одной зависимости.

protocol TestProtocol: class {
    associatedtype Dependencies
    func inject(_ dependency: Dependencies)
}

protocol HasSomething {
    var something: Something { get set }
}

protocol HasSomethingElse {
    var somethingElse: SomethingElse { get set }
}

Чтобы использовать это, я обнаружил, что мне нужно будет использовать обобщения типа этого:

class TestService<T> where T: TestProtocol, T.Dependencies == TestService {

    weak var testProtocol: T?

    init(with testProtocol: T) {
        self.testProtocol = testProtocol        
        self.testProtocol?.inject(self)
    }
}

Теперь, когда я хочу использовать эту службу где-то еще и пытаюсь ее запустить, у меня возникает следующая проблема:

problem with generics

Параметротображается как _, а не как имя протокола TestProtocol.

Допустим, я бы использовал этот код в библиотеке.Как бы пользователь узнал (не читая, конечно, документацию), какой тип можно использовать в этом контексте, когда он даже не знает, какой протокол он должен реализовать?

Есть ли лучший способ использования зависимостивнедрение с типом, фактически отображаемым пользователю, или я делаю что-то не так в предложении where класса TestService, или это просто невозможно в текущих версиях Swift?

Ответы [ 2 ]

1 голос
/ 11 июля 2019

В вашем коде нет ничего плохого, это просто невозможно.

class TestService<T> where T: TestProtocol

Предложение where означает, что T может быть чем угодно, с тем ограничением, что данный объект должен соответствует TestProtocol.

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

У вас точно такая же проблема в стандартной библиотеке swift, с Dictionary, например,

public struct Dictionary<Key, Value> where Key : Hashable {

  public init(dictionaryLiteral elements: (Key, Value)...) {
    // ..
  }
}

Универсальный Key в качестве ограничения Hashable, но Xcode по-прежнему показывает _ в списке автозаполнения.

image (dictionaryLiteral: (_, _)...)">

Я предполагаю, что разработчики Swift используют это поведение, поэтому оно не будетбудет большой проблемой, даже если ваш код встроен в библиотеку.

Как пользователь узнает (конечно, не читая документацию), какой тип можно использовать в этом контексте, когда он даже незная, какой протокол он должен реализоватьMent?

Потому что Xcode довольно ясно говорит о требованиях к протоколу.Если я попытаюсь инициализировать TestService с помощью String, я получу сообщение об ошибке:

Referencing initializer 'init(with:)' on 'TestService' requires that 'String' conform to 'TestProtocol'

Что само собой разумеется.

0 голосов
/ 10 июля 2019

На самом деле во время init(with testProtocol: T) Компилятор, конечно, не знает о T, потому что это универсальный

, если вы предоставите непосредственно класс, он покажет вам в предложении

Дляпример

class TestService<T:Something>  {

    weak var testProtocol: T?

    init(with testProtocol: T) {
        self.testProtocol = testProtocol
    }

}

Теперь вы увидите, что компилятор знает, что ему нужно SomeThing в T

enter image description here


Для вашего случая Для TestProtocol Вы можете заменить на чем-то понятным пользователю.в следующий раз компилятор предоставит вам указанный тип в качестве предложения

Например:

class TestService<T:TestProtocol>  {

    weak var testProtocol: T?

    init(with testProtocol: T) {
        self.testProtocol = testProtocol
    }

    func add(t:T) {

    }
}

class Test {

    init() {
        let t = Something()

        let ts = TestService(with: t)



    }
}

В Test классе вы можете ввести ts.add, теперь он знает

enter image description here

...