Inheritance Swift协议继承&;泛型函数
考虑以下游乐场:Inheritance Swift协议继承&;泛型函数,inheritance,swift,protocols,swift-playground,Inheritance,Swift,Protocols,Swift Playground,考虑以下游乐场: import Foundation protocol StringInitable { init( string:String ) } class A : StringInitable { var stored:String required init ( string:String ) { stored = string } } class B : A /*, StringInitable */ { var an
import Foundation
protocol StringInitable {
init( string:String )
}
class A : StringInitable {
var stored:String
required init ( string:String ) {
stored = string
}
}
class B : A /*, StringInitable */ {
var another_stored:String
required init ( string:String ) {
another_stored = "B-store"
super.init(string: string)
}
}
func maker<T:StringInitable>(string:String) -> T {
return T(string: string)
}
let instanceA = A(string: "test-maker-A")
let instanceB = B(string: "test-maker-B")
let makerA:A = maker("test-maker-A")
let makerB:B = maker("test-maker-B")
let typeInstanceA = _stdlib_getTypeName(instanceA)
let typeMakerA = _stdlib_getTypeName(makerA)
let typeInstanceB = _stdlib_getTypeName(instanceB)
let typeMakerB = _stdlib_getTypeName(makerB)
<代码>导入基础
协议StringInitable{
初始化(字符串:字符串)
}
A类:StringInitable{
存储的变量:字符串
必需的初始化(字符串:字符串){
存储=字符串
}
}
B类:A/*,StringInitable*/{
存储的变量:String
必需的初始化(字符串:字符串){
另一个_stored=“B-store”
super.init(string:string)
}
}
函数生成器(字符串:字符串)->T{
返回T(字符串:字符串)
}
让instanceA=A(字符串:“test-maker-A”)
让instanceB=B(字符串:“test-maker-B”)
设makerA:A=maker(“test-maker-A”)
设makerB:B=maker(“test-maker-B”)
让typeInstanceA=\u stdlib\u getTypeName(instanceA)
让typeMakerA=\u stdlib\u getTypeName(makerA)
让typeInstanceB=\u stdlib\u getTypeName(instanceB)
让typeMakerB=\u stdlib\u getTypeName(makerB)
从结果中,编译器似乎推断出了正确的类型,但未能调用正确的初始值设定项。为什么我必须在B类中显式实现StringInitable(通过删除B类定义中的注释进行测试),才能让泛型函数“maker”调用正确的初始值设定项?这听起来像编译器错误,原因很简单:
makerB
是B
类型的变量,但是它被分配了一个A
的实例。这应该是不可能的,事实上,如果您尝试打印makerB
变量的另一个存储的属性,并且更一般地访问该属性,则会引发运行时异常,我不希望发生其他情况
这是因为如果B
是a
的子类,a
的实例不能分配给B
类型的变量(反之亦然)
虽然可以将a
类型的变量分配给B
类型的变量,但仅在以下条件下:
- 从
A
到B
的显式向下转换已完成(否则编译器将出错)
A
变量引用的实例实际上是B
的实例(否则应引发运行时异常)
请注意,编译器并不是没有调用正确的初始值设定项,而是调用了另一个类的初始值设定项一旦我在init函数前面添加了“required”说明符,它就为我工作了。