我在Swift上为owner / ownee方案建模:
class Owner<T: Ownee> {
// ...
}
protocol Ownee {
var owner: Owner<Self> { get }
}
然后我有一对班级教授/学生坚持上面的建模类型:
class Professor: Owner<Student> {
// ...
}
class Student: Ownee {
let professor: Professor
var owner: Owner<Student> { // error here (see below)
return professor
}
init(professor: Professor) {
self.professor = professor
}
}
但是我在定义上得到以下错误 var owner
在里面 Student
类:
协议'Ownee'要求'所有者'不能满足
非最终类('学生'),因为它在非参数中使用'Self',
非结果类型的位置
我试图了解这个错误的原因是什么,为什么要上课 Student
最终会修复它,如果有一些解决方法能够以不同的方式对其进行建模,而不是使这个类最终。我已经用Google搜索了这个错误,但到目前为止还没有找到太多。
错误是正确的。你必须让你的类最终,因为没有子类可以符合你的协议 Ownee
。
考虑这个子类:
class FirstGradeStudent: Student {
// inherited from parent
// var owner: Owner<Student> {
// return professor
// }
}
如您所见,它必须实现 var owner: Owner<Student>
因为他的父母,但它应该实施 var owner: Owner<FirstGradeStudent>
相反,因为协议包含 var owner: Owner<Self> { get }
在这种情况下 Self
将会 FirstGradeStudent
。
解决方法
1: 定义一个超类 Ownee
,它应该被使用 Owner
:
class Owner<T: OwneeSuper> {
// ...
}
protocol OwneeSuper {}
protocol Ownee: OwneeSuper {
associatedtype T: OwneeSuper
var owner: Owner<T> { get }
}
OwneeSuper
只是一个需要克服的解决方法 这个问题,否则我们只会使用:
protocol Ownee {
associatedtype T: Ownee
var owner: Owner<T> { get }
}
2。 在符合的类中 Ownee
,你必须转动抽象类型 associatedtype
通过定义一个具体的类 typealias
:
class Student: Ownee {
typealias T = Student // <<-- define the property to be Owner<Student>
let professor: Professor
var owner: Owner<T> {
return professor
}
init(professor: Professor) {
self.professor = professor
}
}
3。 子类现在可以使用属性,该属性将是您定义的类型:
class FirstGradeStudent: Student {
func checkOwnerType() {
if self.owner is Owner<Student> { //warning: 'is' test is always true
print("yeah!")
}
}
}
如果发生了什么 Student
是子类?业主财产仍然存在 Owner<Student>
但是 Student != StudentSubclass
。
通过制作你的 Student
班级符合 Ownee
协议,您必须满足协议的合同。该 Ownee
协议声明 Owner
有类型约束,这样的 Owner
泛型类型是符合的类型 Ownee
(Student
, 在这种情况下)。
如果编译器允许子类化(即允许你不进行子类化) Student
最后),那么就有可能了 StudentSubclass
存在。这样的子类将继承 Owner
财产,类型 Owner<Student>
但是 Student
是不一样的 StudentSubclass
。该 Ownee
协议的合同已被破坏,因此,不允许存在这样的子类。
以下语法应该支持您所追求的内容:
protocol Ownee {
associatedtype Owned = Self where Owned:Ownee
var owner: Owner<Owned> { get }
}
(使用Swift 4测试 - Beta 1)
如果你来这个线程只是想找到一种方法让子类继承一个引用它自己的类型(Self类型)的方法,一个解决方法是参数化子类型的父类。例如
class Foo<T> {
func configure(_ block: @escaping (T)->Void) { }
}
class Bar: Foo<Bar> { }
Bar().configure { $0... }
但是......似乎您可以在协议扩展中添加一个方法,该方法不会被认为符合协议本身。我不完全理解为什么会这样:
protocol Configurable {
// Cannot include the method in the protocol definition
//func configure(_ block: @escaping (Self)->Void)
}
public extension Configurable {
func configure(_ block: @escaping (Self)->Void) { }
}
class Foo: Configurable { }
class Bar: Foo { }
Bar().configure { $0... }
如果您取消对协议定义本身中的方法的注释,您将获得 Protocol 'Configurable' requirement 'configure' cannot be satisfied by a non-final class ('Foo') because it uses 'Self' in a non-parameter, non-result type position
编译错误。