我想在协议中指定一个函数,其返回值与当前实现类的类型匹配。
var foos = document.body.querySelectorAll(".foo");
foos.forEach(function (item) {
item.addEventListener("click", () => {
console.log(item);
});
});
除非T被约束为实现MakesSelf的同类型,例如
protocol MakesSelf {
static func getInstance<T>() -> T
}
我理解编译器会根据返回值为T分配MyThing的类型,但我得到的是类型转换错误:class MyThing: MakesSelf {
class func getInstance<T>() -> T {
return MyThing()
}
}
答案 0 :(得分:2)
您可以创建一个具有关联类型的协议,其中getInstance()
函数将返回该类型。在协议的扩展中,创建该函数的默认实现。完整的例子:
protocol Initializable {
init()
}
protocol MakesSelf: Initializable {
associatedtype Object: Initializable = Self
static func getInstance() -> Object
}
extension MakesSelf {
static func getInstance() -> Object {
return Object()
}
}
class MyThing: MakesSelf {
required init() {}
func printSelf() {
print(MyThing.self)
print(Object.self)
// Both will print "MyThing" because Object is a typealias of MyThing class
}
}
然后获取您的实例:
let instance = MyThing.getInstance()
print("\(instance.self)")
/* Will print: MyTestApp.MyThing */
正如您所看到的,因为您已经在协议扩展中提供了getInstance()
的默认实现,而这在合规类中是不必要的。在您的问题的上下文中,关联类型充当“占位符”。
答案 1 :(得分:0)
我遇到的问题是在T
的情况下无法推断MyThing
。当涉及到错误消息时,编译器并不是非常有帮助(有一次我被告知Cannot convert return expression of type 'T' (aka 'MyImplementation') to return type 'T'
)
解决方案是为编译器提供一些方法来了解T
应该是什么(如果你想要它不受限制,使用AnyObject
,而不是T
)。
在我的情况下,我想返回Self类型的值(实现&#39; s类型)。这比正常的POP问题更复杂,因为你不能在类/静态函数中引用Self。
为了解决这个问题,我使用了Swift的associatedtype
,它允许我们设置一个命名的占位符,以便在协议中使用。由于我们在协议级别定义了这个并提供了一个值,因此我们可以设置一个对实现者自己的类型的命名引用。
associatedtype MyType = Self.Type
注意 associatedtype MyType = Self
不起作用,因为此上下文中的self 是协议,而不是最终实现的类型(我们不知道#39;我们知道,我们/编译器不知道,直到某个对象实际实现了协议。)
由于我们提供了一个值,当我们实现我们的协议时,类型已经受到约束!由于约束仅涉及实现的类型,因此实现协议足以定义类型(酷)。最好的部分是现在我可以在我的class func
定义中删除引用Self:
protocol MakesSelf {
associatedtype MyType = Self.Type
static func getInstance() -> MyType
}
class MyImplementation: MakesSelf {
class func getInstance() -> MyImplementation {
print("Hello")
return MyImplementation()
}
}
let myThing = MyImplementation.getInstance()
这里要非常清楚 - 类MyImplementation有一个名为MyType的类型,由协议指定。编译时,别名将引用当前的实现。现在,当我实现函数getInstance时,MyImplementation符合MyType。
注意我必须以class func getInstance() -> MyImplementation
而不是class func getInstance() -> MyType
的形式编写我的功能签名。这是因为我返回函数调用MyImplementation()
的结果,这恰好符合MyType的约束。这与MyImplementation隐式转换为MyType的说法不同。
关于尝试制作protocol function specification for returning self see here的好读物,但我想发布具体的解决方案和解释。