[英]A Swift protocol requirement that can only be satisfied by using a final class
I'm modeling a owner/ownee scheme on Swift: 我在Swift上为owner / ownee方案建模:
class Owner<T: Ownee> {
// ...
}
protocol Ownee {
var owner: Owner<Self> { get }
}
Then I have a pair of classes professor/student that adhere to the modeled types above: 然后我有一对班级教授/学生遵守上面的建模类型:
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
}
}
However I get the following error on the definition of var owner
in the Student
class: 但是,我在Student
类的var owner
定义中收到以下错误:
Protocol 'Ownee' requirement 'owner' cannot be satisfied by a non-final class ('Student') because it uses 'Self' in a non-parameter, non-result type position 协议'Ownee'要求'所有者'不能被非最终类('学生')满足,因为它在非参数非结果类型位置使用'Self'
I'm trying to understand what's the cause for this error, why making the class Student
final would fix it, and if there's some workaround to be able to model this differently, without making this class final. 我试图理解这个错误的原因是什么,为什么让Student
最终的类会修复它,如果有一些解决方法能够以不同的方式对其进行建模,而不是让这个类最终。 I've googled about that error, but haven't found much so far. 我已经搜索了这个错误,但到目前为止还没有找到太多。
The Error is correct. 错误是正确的。 You have to make your class final, since no subclasses could conform your protocol Ownee
. 你必须让你的课成为最终,因为没有子类可以符合你的协议Ownee
。
Consider this subclass: 考虑这个子类:
class FirstGradeStudent: Student {
// inherited from parent
// var owner: Owner<Student> {
// return professor
// }
}
As you can see, it would have to implement var owner: Owner<Student>
because of his parent, but it should be implementing var owner: Owner<FirstGradeStudent>
instead, because the protocol contains var owner: Owner<Self> { get }
and in this case Self
would be FirstGradeStudent
. 正如您所看到的,它必须实现var owner: Owner<Student>
因为他的父级,但它应该实现var owner: Owner<FirstGradeStudent>
,因为协议包含var owner: Owner<Self> { get }
在这种情况下, Self
将成为FirstGradeStudent
。
Workaround 解决方法
1: Define a superclass to Ownee
, it should be used by Owner
: 1:为Ownee
定义一个超类,它应该由Owner
:
class Owner<T: OwneeSuper> {
// ...
}
protocol OwneeSuper {}
protocol Ownee: OwneeSuper {
associatedtype T: OwneeSuper
var owner: Owner<T> { get }
}
OwneeSuper
is just a workaround to overcome this problem , otherwise we would just be using: OwneeSuper
只是解决这个问题的一种解决方法,否则我们只会使用:
protocol Ownee {
associatedtype T: Ownee
var owner: Owner<T> { get }
}
2. In classes that conform to Ownee
, you must turn the abstract type of the associatedtype
into a concrete class by defining a typealias
: 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. Subclasses can now make use of the property, which will be of your defined type: 3.子类现在可以使用属性,该属性将是您定义的类型:
class FirstGradeStudent: Student {
func checkOwnerType() {
if self.owner is Owner<Student> { //warning: 'is' test is always true
print("yeah!")
}
}
}
What happens if Student
is subclassed? 如果Student
是子类,会发生什么? The owner property remains Owner<Student>
, but Student != StudentSubclass
. 所有者属性仍为Owner<Student>
,但Student != StudentSubclass
。
By making your Student
class conform to the Ownee
protocol, you must satisfy the contract of the protocol. 通过使您的Student
类符合Ownee
协议,您必须满足协议的合同。 The Ownee
protocol states that Owner
has type constraint, such that the Owner
generic type is the type that's conforming to Ownee
( Student
, in this case). Ownee
协议声明Owner
具有类型约束,因此Owner
泛型类型是符合Ownee
(在这种情况下为Student
)的类型。
If the compiler were to allow subclassing (ie by allowing you to not make Student
final), then it would be possible for a StudentSubclass
to exist. 如果编译器允许子类化(即允许你不让Student
终结),那么StudentSubclass
可能存在。 Such a subclass would inherit the Owner
property, of type Owner<Student>
, but Student
is not the same as StudentSubclass
. 这样的子类将继承Owner<Student>
类型的Owner
属性,但Student
与StudentSubclass
。 The Ownee
protocol's contract has been breached, thus, such a subclass cannot be allowed to exist. Ownee
协议的合同已被破坏,因此,不允许存在这样的子类。
The following syntax should support what you're after: 以下语法应该支持您所追求的内容:
protocol Ownee {
associatedtype Owned = Self where Owned:Ownee
var owner: Owner<Owned> { get }
}
(tested using Swift 4 - Beta 1) (使用Swift 4测试 - Beta 1)
If you are coming to this thread just looking for a way to have subclasses inherit a method referring to its own type (type of Self) one workaround would be to parameterize the parent class on the child's type. 如果你来这个线程只是想找到一种方法让子类继承一个引用它自己的类型(Self类型)的方法,一种解决方法是参数化子类型的父类。 eg 例如
class Foo<T> {
func configure(_ block: @escaping (T)->Void) { }
}
class Bar: Foo<Bar> { }
Bar().configure { $0... }
BUT... it also seems that you can add a method in a protocol extension that would not be considered to conform in the protocol itself. 但是......似乎您可以在协议扩展中添加一个方法,该方法在协议本身中不会被认为是符合的。 I don't fully understand why this works: 我不完全理解为什么会这样:
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... }
If you uncomment the method in the protocol definition itself you'll get the 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
compile error. 如果您取消对协议定义本身中的方法的注释,您将获得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
编译错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.