type - swift variables
Protocolo Swift con error de tipo asociado asociado "Tipo no es convertible" (1)
El error ocurre porque ManagerReaderType
en la función de read
es solo un marcador de posición genérico para cualquier tipo que se ajuste a Reader
y su ReaderValueType
es igual al de ManagerReaderType
. Entonces, el tipo real de ManagerReaderType
no está determinado por la función en sí, sino que el tipo de la variable que se asigna declara el tipo:
let manager = Manager1()
let reader1: Reader1? = manager.read() // ManagerReaderType is of type Reader1
let reader2: Reader2? = manager.read() // ManagerReaderType is of type Reader2
si devuelve nil
, puede convertirse a cualquier tipo opcional para que siempre funcione.
Como alternativa, puede devolver un tipo específico de Reader
de tipo:
protocol Manager {
// this is similar to the Generator of a SequenceType which has the Element type
// but it constraints the ManagerReaderType to one specific Reader
typealias ManagerReaderType: Reader
func read() -> ManagerReaderType?
}
class Manager1: Manager {
func read() -> Reader1? {
return Reader1()
}
}
Este es el mejor enfoque con protocolos debido a la falta de genéricos "verdaderos" (el siguiente no es compatible (todavía)):
// this would perfectly match your requirements
protocol Reader<T: Value> {
fun value() -> T
}
protocol Manager<T: Value> {
func read() -> Reader<T>?
}
class Manager1: Manager<Value1> {
func read() -> Reader<Value1>? {
return Reader1()
}
}
Por lo tanto, la mejor solución sería hacer de Reader
una clase genérica y las clases de Reader1
y Reader2
un tipo genérico específico:
class Reader<T: Value> {
func value() -> T {
// or provide a dummy value
fatalError("implement me")
}
}
// a small change in the function signature
protocol Manager {
typealias ManagerValueType: Value
func read() -> Reader<ManagerValueType>?
}
class Reader1: Reader<Value1> {
override func value() -> Value1 {
return Value1()
}
}
class Reader2: Reader<Value2> {
override func value() -> Value2 {
return Value2()
}
}
class Manager1: Manager {
typealias ManagerValueType = Value1
func read() -> Reader<ManagerValueType>? {
return Reader1()
}
}
let manager = Manager1()
// you have to cast it, otherwise it is of type Reader<Value1>
let a: Reader1? = manager.read() as! Reader1?
Esta implementación debería resolver su problema, pero ahora los Readers
son tipos de referencia y se debe considerar una función de copia.
Creé 2 protocolos con tipos asociados. Un tipo conforme a Reader
debería ser capaz de producir una instancia de un tipo conforme a Value
.
La capa de complejidad proviene de un tipo que se ajusta al Manager
debe ser capaz de producir una instancia concreta de Reader
que produce un tipo específico de Value
(ya sea Value2
o Value2
).
Con mi implementación concreta de Manager1
me gustaría que siempre produzca Reader1
que a su vez produce instancias de Value1
.
¿Podría alguien explicar por qué?
"Reader1 no es convertible a ManagedReaderType?"
Cuando la línea errónea se cambia a (por ahora) return nil
, todo se compila muy bien, pero ahora no puedo instanciar Reader1
o Reader2
.
Lo siguiente se puede pegar en un área de juegos para ver el error:
import Foundation
protocol Value {
var value: Int { get }
}
protocol Reader {
typealias ReaderValueType: Value
func value() -> ReaderValueType
}
protocol Manager {
typealias ManagerValueType: Value
func read<ManagerReaderType: Reader where ManagerReaderType.ReaderValueType == ManagerValueType>() -> ManagerReaderType?
}
struct Value1: Value {
let value: Int = 1
}
struct Value2: Value {
let value: Int = 2
}
struct Reader1: Reader {
func value() -> Value1 {
return Value1()
}
}
struct Reader2: Reader {
func value() -> Value2 {
return Value2()
}
}
class Manager1: Manager {
typealias ManagerValueType = Value1
let v = ManagerValueType()
func read<ManagerReaderType: Reader where ManagerReaderType.ReaderValueType == ManagerValueType>() -> ManagerReaderType? {
return Reader1()// Error: "Reader1 is not convertible to ManagedReaderType?" Try swapping to return nil which does compile.
}
}
let manager = Manager1()
let v = manager.v.value
let a: Reader1? = manager.read()
a.dynamicType