Swift 具有约束关联类型错误的协议 "Type is not convertible"
Swift protocol with constrained associated type error "Type is not convertible"
我已经创建了 2 个具有关联类型的协议。符合 Reader
的类型应该能够生成符合 Value
.
的类型的实例
复杂层来自符合 Manager
的类型应该能够生成具体的 Reader
实例,该实例生成特定类型的 Value
(Value1
或 Value2
).
通过我对 Manager1
的具体实现,我希望它始终生成 Reader1
,进而生成 Value1
.
的实例
谁能解释一下为什么
"Reader1 is not convertible to ManagedReaderType?"
当错误行更改为(暂时)return nil
时,所有编译都很好,但现在我无法实例化 Reader1
或 Reader2
.
可以将以下内容粘贴到Playground中查看错误:
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
错误发生是因为read
函数中的ManagerReaderType
只是任何符合Reader
的类型的通用占位符,它的ReaderValueType
等于那个ManagerReaderType
个。所以 ManagerReaderType
的实际类型不是由函数本身决定的,而是被赋值的变量的类型声明了类型:
let manager = Manager1()
let reader1: Reader1? = manager.read() // ManagerReaderType is of type Reader1
let reader2: Reader2? = manager.read() // ManagerReaderType is of type Reader2
如果您 return nil
它可以转换为任何可选类型,因此它始终有效。
作为替代方案,您可以 return 特定类型的类型 Reader
:
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()
}
}
这是最好的协议方法,因为缺少 "true" 泛型(以下不支持(尚)):
// 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()
}
}
所以最好的解决方法是使 Reader
成为泛型 class 并且 Reader1
和 Reader2
subclass 成为它的特定泛型类型:
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?
这个实现应该可以解决您的问题,但是 Readers
现在是引用类型,应该考虑复制函数。
我已经创建了 2 个具有关联类型的协议。符合 Reader
的类型应该能够生成符合 Value
.
复杂层来自符合 Manager
的类型应该能够生成具体的 Reader
实例,该实例生成特定类型的 Value
(Value1
或 Value2
).
通过我对 Manager1
的具体实现,我希望它始终生成 Reader1
,进而生成 Value1
.
谁能解释一下为什么
"Reader1 is not convertible to ManagedReaderType?"
当错误行更改为(暂时)return nil
时,所有编译都很好,但现在我无法实例化 Reader1
或 Reader2
.
可以将以下内容粘贴到Playground中查看错误:
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
错误发生是因为read
函数中的ManagerReaderType
只是任何符合Reader
的类型的通用占位符,它的ReaderValueType
等于那个ManagerReaderType
个。所以 ManagerReaderType
的实际类型不是由函数本身决定的,而是被赋值的变量的类型声明了类型:
let manager = Manager1()
let reader1: Reader1? = manager.read() // ManagerReaderType is of type Reader1
let reader2: Reader2? = manager.read() // ManagerReaderType is of type Reader2
如果您 return nil
它可以转换为任何可选类型,因此它始终有效。
作为替代方案,您可以 return 特定类型的类型 Reader
:
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()
}
}
这是最好的协议方法,因为缺少 "true" 泛型(以下不支持(尚)):
// 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()
}
}
所以最好的解决方法是使 Reader
成为泛型 class 并且 Reader1
和 Reader2
subclass 成为它的特定泛型类型:
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?
这个实现应该可以解决您的问题,但是 Readers
现在是引用类型,应该考虑复制函数。