关联类型的依赖注入导致 Swift 中没有类型名称(下划线)的参数
Dependency injection with associated types causing arguments without type names (undescores) in Swift
情况如下:我正在使用一个协议来注入依赖项,我发现在 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)
}
}
现在,当我想在其他地方使用此服务并尝试启动它时,我遇到了以下问题:
参数显示为 _
而不是协议名称 TestProtocol
。
假设我将在库中使用此代码。当用户甚至不知道他必须实现什么协议时,他怎么知道(当然不阅读文档)在这种情况下可以使用什么类型?
是否有更好的方法来使用依赖注入实际显示给用户的类型,或者我在 TestService
[=34] 的 where
子句中做错了什么=],或者这在 Swift 的当前版本中根本不可能吗?
实际上在 init(with testProtocol: T)
编译器不知道 T
当然因为它是通用的
如果您直接提供 class 它会在建议中显示您
例如
class TestService<T:Something> {
weak var testProtocol: T?
init(with testProtocol: T) {
self.testProtocol = testProtocol
}
}
现在你会看到编译器知道它需要 SomeThing
在 T
对于你的情况对于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
class中你可以输入ts.add现在它知道了
你的代码没有问题,这根本不可能。
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 仍然在自动完成列表中显示 _
。
我想 Swift 开发人员已经习惯了这种行为,所以这不会是一个大问题,即使您的代码嵌入到库中也是如此。
How would a user know (without reading the documentation of course) what type could be used in this context when he is not even knowing what protocol he has to implement?
因为Xcode协议要求已经很清楚了。
如果我尝试用 String
初始化 TestService
我会得到错误:
Referencing initializer 'init(with:)' on 'TestService' requires that 'String' conform to 'TestProtocol'
这是不言自明的。
情况如下:我正在使用一个协议来注入依赖项,我发现在 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)
}
}
现在,当我想在其他地方使用此服务并尝试启动它时,我遇到了以下问题:
参数显示为 _
而不是协议名称 TestProtocol
。
假设我将在库中使用此代码。当用户甚至不知道他必须实现什么协议时,他怎么知道(当然不阅读文档)在这种情况下可以使用什么类型?
是否有更好的方法来使用依赖注入实际显示给用户的类型,或者我在 TestService
[=34] 的 where
子句中做错了什么=],或者这在 Swift 的当前版本中根本不可能吗?
实际上在 init(with testProtocol: T)
编译器不知道 T
当然因为它是通用的
如果您直接提供 class 它会在建议中显示您
例如
class TestService<T:Something> {
weak var testProtocol: T?
init(with testProtocol: T) {
self.testProtocol = testProtocol
}
}
现在你会看到编译器知道它需要 SomeThing
在 T
对于你的情况对于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
class中你可以输入ts.add现在它知道了
你的代码没有问题,这根本不可能。
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 仍然在自动完成列表中显示 _
。
我想 Swift 开发人员已经习惯了这种行为,所以这不会是一个大问题,即使您的代码嵌入到库中也是如此。
How would a user know (without reading the documentation of course) what type could be used in this context when he is not even knowing what protocol he has to implement?
因为Xcode协议要求已经很清楚了。
如果我尝试用 String
初始化 TestService
我会得到错误:
Referencing initializer 'init(with:)' on 'TestService' requires that 'String' conform to 'TestProtocol'
这是不言自明的。