本文介绍了具有约束关联类型错误的Swift协议“类型不可转换”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了2个关联类型的协议。符合 Reader 的类型应该能够生成符合 Value 的类型实例。



复杂层来自符合的类型Manager> 应该能够产生具体的 Reader 产生特定类型的值(或者 Value1 或者 Value2 )。



使用 Manager1 的具体实现,我希望它始终产生 Reader1 ,这又产生 Value1 的实例。



有人可以解释为什么

当错误行改为(现在)返回 nil 它全部编译得很好,但现在我不能实例化 Reader1 或 Reader2 。



以下内容可以粘贴到Playground中以查看错误:

  import Foundation 

协议值{
var value:Int {get}
}

协议读取器{
typealias ReaderValueType:Value
func value() - > ReaderValueType


协议管理器{
typealias ManagerValueType:Value

func read< ManagerReaderType:Reader其中ManagerReaderType.ReaderValueType == ManagerValueType>() - > ManagerReaderType?

$ b $ struct结构Value1:Value {
let value:Int = 1
}

struct Value2:Value {
让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其中ManagerReaderType.ReaderValueType == ManagerValueType>() - > ManagerReaderType? {
返回Reader1()//错误:Reader1不能转换为ManagedReaderType?尝试交换返回无编译的nil。
}
}

let manager = Manager1()
let v = manager.v.value
let a:Reader1? = manager.read()
.dynamicType


解决方案

由于 ManagerReaderType 在 read 函数中只是任何类型的通用占位符,符合 Reader 及其 ReaderValueType 等于 ManagerReaderType 之一。因此, ManagerReaderType 的实际类型不是由函数本身决定的,而是被赋值的变量的类型声明了类型:

  let manager = Manager1()
let reader1:Reader1? = manager.read()// ManagerReaderType的类型为Reader1
let reader2:Reader2? = manager.read()// ManagerReaderType的类型为Reader2

如果返回 nil 它可以转换为任何可选类型,因此它总能正常工作。



作为替代方案,您可以返回特定类型的类型 Reader :

 协议管理器{
//这与SequenceType的生成器,其元素类型为
//但它将ManagerReaderType限制为一个特定的Reader
typealias ManagerReaderType:Reader

func read() - > ManagerReaderType?
}

class Manager1:Manager {

func read() - > Reader1? {
return Reader1()
}
}

这是由于缺乏真正的泛型,协议的最佳方法(以下不支持(尚)):

pre $ //这将完全符合您的要求
协议Reader< T:Value> {
fun value() - > T
}

协议管理器< T:值> {
func read() - >读取器LT; T> ;?
}

class Manager1:Manager< Value1> {
func read() - >读取器LT;值1> ;? {
return Reader1()
}
}

最好的解决方法是使 Reader 一个通用类, Reader1 和 Reader2

  class Reader< T:Value> {
func value() - > T {
//或提供一个虚拟值
fatalError(实现我)
}
}

//函数的一个小改动签名
协议管理器{
typealias ManagerValueType:值
func read() - >读取器LT; ManagerValueType> ;?
}

class Reader1:Reader< Value1> {
覆盖func value() - > Value1 {
return Value1()
}
}

class Reader2:Reader< Value2> {
覆盖func value() - > Value2 {
return Value2()
}
}

class Manager1:Manager {
typealias ManagerValueType = Value1

func read() - >读取器LT; ManagerValueType> ;? {
return Reader1()
}
}

让manager = Manager1()

//你必须抛出它,否则它是类型Reader< Value1>
让a:Reader1? = manager.read()as! Reader1?

这个实现应该可以解决你的问题,但是读者现在是引用类型,应考虑复制功能。


I have created 2 protocols with associated types. A type conforming to Reader should be able to produce an instance of a type conforming to Value.

The layer of complexity comes from a type conforming to Manager should be able to produce a concrete Reader instance which produces a specific type of Value (either Value1 or Value2).

With my concrete implementation of Manager1 I'd like it to always produce Reader1 which in turn produces instances of Value1.

Could someone explain why

When the erroneous line is changed to (for now) return nil it all compiles just fine but now I can't instantiate either Reader1 or Reader2.

The following can be pasted into a Playground to see the 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
解决方案

The error occurs because ManagerReaderType in the read function is only a generic placeholder for any type which conforms to Reader and its ReaderValueType is equal to the one of ManagerReaderType. So the actual type of ManagerReaderType is not determined by the function itself, instead the type of the variable which gets assigned declares the type:

let manager = Manager1()
let reader1: Reader1? = manager.read() // ManagerReaderType is of type Reader1
let reader2: Reader2? = manager.read() // ManagerReaderType is of type Reader2

if you return nil it can be converted to any optional type so it always works.

As an alternative you can return a specific type of type 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()
    }
}

This is the best approach with protocols due to the lack of "true" generics (the following isn't supported (yet)):

// 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()
    }
}

So the best workaround would be to make Reader a generic class and Reader1 and Reader2 subclass a specific generic type of it:

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?

This implementation should solve you problem, but the Readers are now reference types and a copy function should be considered.

这篇关于具有约束关联类型错误的Swift协议“类型不可转换”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 03:58