小编典典

只能通过使用最终类才能满足的Swift协议要求

swift

我在Swift上建模所有者/所有者方案:

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 ownerStudent类中的定义上收到以下错误:

非最终课程(“学生”)无法满足协议“ Ownee”的要求“所有者”,因为它在非参数,非结果类型的位置使用了“自我”

我试图了解导致此错误的原因,为什么将类定为Studentfinal可以解决该问题,以及是否存在一些解决方法能够以不同的方式对此模型进行建模而不将其定为final。我已经搜索过该错误,但到目前为止还没有发现太多。


阅读 206

收藏
2020-07-07

共1个答案

小编典典

错误是正确的。您必须将类定型,因为没有子类可以符合您的协议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 },在这种情况下SelfFirstGradeStudent

解决方法

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!")
        }
    }
}
2020-07-07