tuple - Un requisito de protocolo Swift que solo se puede satisfacer utilizando una clase final
tuple swift (3)
¿Qué sucede si el Student
está subclasificado? La propiedad del propietario sigue siendo Owner<Student>
, pero Student != StudentSubclass
.
Al hacer que su clase de Student
ajuste al protocolo de Ownee
, debe cumplir con el contrato del protocolo. El protocolo de Ownee
establece que el Owner
tiene una restricción de tipo, de modo que el tipo genérico de Owner
es del tipo que se ajusta a Ownee
( Student
, en este caso).
Si el compilador permitiera la creación de subclases (es decir, permitiéndole no hacer que el Student
final), entonces sería posible que exista una StudentSubclass
de StudentSubclass
de StudentSubclass
. Dicha subclase heredará la propiedad Owner
, de tipo Owner<Student>
, pero Student
no es lo mismo que StudentSubclass
. El Ownee
protocolo de Ownee
ha sido violado, por lo tanto, no se puede permitir que exista dicha subclase.
Estoy modelando un esquema propietario / propietario en Swift:
class Owner<T: Ownee> {
// ...
}
protocol Ownee {
var owner: Owner<Self> { get }
}
Luego tengo un par de clases profesor / alumno que se adhieren a los tipos de modelos anteriores:
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
}
}
Sin embargo, aparece el siguiente error en la definición de var owner
de var owner
en la clase de Student
:
El requisito ''propietario'' del protocolo ''Ownee'' no puede ser satisfecho por una clase no final (''Estudiante'') porque usa ''Auto'' en una posición sin parámetro y sin resultado
Intento entender cuál es la causa de este error, por qué hacer que la clase Student
final lo arregle, y si hay alguna solución para poder modelar esto de manera diferente, sin hacer que esta clase sea definitiva. Busqué en Google ese error, pero hasta ahora no he encontrado demasiado.
El error es correcto Tienes que hacer que tu clase sea definitiva, ya que ninguna subclase podría conformar tu protocolo Ownee
.
Considera esta subclase:
class FirstGradeStudent: Student {
// inherited from parent
// var owner: Owner<Student> {
// return professor
// }
}
Como puede ver, tendría que implementar el var owner: Owner<Student>
debido a su padre, pero debería implementar el var owner: Owner<FirstGradeStudent>
, porque el protocolo contiene var owner: Owner<Self> { get }
y en este caso, Self
sería FirstGradeStudent
.
Solución
1: defina una superclase para Ownee
, debe ser utilizada por el Owner
:
class Owner<T: OwneeSuper> {
// ...
}
protocol OwneeSuper {}
protocol Ownee: OwneeSuper {
associatedtype T: OwneeSuper
var owner: Owner<T> { get }
}
OwneeSuper
es solo una solución para superar este problema , de lo contrario solo estaríamos usando:
protocol Ownee {
associatedtype T: Ownee
var owner: Owner<T> { get }
}
2. En las clases que se ajustan a Ownee
, debe convertir el tipo abstracto del tipo associatedtype
en una clase concreta definiendo una 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. Las subclases ahora pueden hacer uso de la propiedad, que será de su tipo definido:
class FirstGradeStudent: Student {
func checkOwnerType() {
if self.owner is Owner<Student> { //warning: ''is'' test is always true
print("yeah!")
}
}
}
La siguiente sintaxis debe ser compatible con lo que busca:
protocol Ownee {
associatedtype Owned = Self where Owned:Ownee
var owner: Owner<Owned> { get }
}
(probado usando Swift 4 - Beta 1)