无法将类实例分配给其协议类型? [英] Cannot assign class instance to its protocol type?

查看:213
本文介绍了无法将类实例分配给其协议类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请参阅下面的自我举例。编译器报告最后一行(标记为 COMPILE ERROR )的错误,其中我将 SimpleTrain 的实例分配给协议类型(在我最好的判断)符合。我如何使它编译?我做错了什么?

 协议Train {
typealias CarriageType

func addCarriage () - < ShortType:Train:CarriageType)
func shortTrain< ShortType:Train where ShortType.CarriageType == CarriageType>() ShortType
}

class SimpleTrain< T> :train {
typealias CarriageType = T
private var carriageages:[T] = [T]()

func addCarriage(carriage:T){
carriages。 append(carriage)
}

func shortTrain< ShortType:Train where ShortType.CarriageType == CarriageType>() - > ShortType {
let short = SimpleTrain< T>()
short.addCarriage(carriages [0])
return short // COMPILE ERROR:SimpleTrain< T>不能转换为'ShortType'
}
}






EDIT:即使我明确地向下转换了 shortTrain 的上面的返回类型作为 Antonio建议读取以ShortType 返回简短,仍然有调用函数时出现编译错误:

  let s = SimpleTrain< String> ;()
s.addCarriage(Carriage 1)
s.addCarriage(Carriage 2)

让a = s.shortTrain()//错误:将表达式类型'()'转换为类型'Train'
let b = s.shortTrain< SimpleTrain< String>>()//错误:不能显式地专门化通用函数


解决方案

首先,您要阅读 canonical thread 在这里从devforums。



现在转到已编辑的问题:

  let a = s.shortTrain()//错误:无法将表达式类型'()'转换为类型'Train'

这是因为你没有给编译器足够的信息来确定 a 的类型。想想看到的内容:

  func shortTrain< ShortType:Train where ShortType.CarriageType == CarriageType>() - > ShortType {
let a = s.shortTrain()

编译器需要找出类型 a 在编译时,它不能处理抽象类型。它需要一个完全指定的类型 ShortType (一切钉住;所有的泛型指定,所有的类型别名解析)。它看起来周围,它看到一些约束在 ShortType ,但它没有看到任何实际上给一个类型。它所有的是 a ,它不给它任何提示。



不幸的是,明确告诉它你想要发生什么。

 让a:SimpleTrain< String> = s.shortTrain()

这可能与你要做的相反,你现在可以在Swift中做。 Swift团队(多次)表示他们很清楚这些问题与相关类型(以及类型系统中的其他一些相关弱点)。他们特别意识到可以处理这些事情的Scala类型系统,并且与当前的Swift类型系统有很多共同点(虽然在我的经验中,获取复杂的依赖于路径的相关类型在Scala中工作也可能导致头发撕裂)。



也就是说,从你的例子中你并不清楚你打算用这个功能。会有一些火车返回一个不同的类型作为他们的shortTrain()?



我发现这些问题往往在一般情况下爆炸,但往往是相当可解的特定在你面前的应用程序的情况。很难在Swift中用可以解决每个问题的代码构建真正的任意类型,但是当你专注于真正需要的类型时,它通常会奏效。例如,如果 shortTrain()返回 Self ,这显然变得更简单。如果调用者知道所需的结果类型,那么 init(shorten:)可能会处理它。一种协议方法,例如 shortCarriages() - > [CarriageType] 可以提供一个好的桥梁。保持您的设计灵活性,其中一个几乎肯定会解决。


Please see self containing example below. Compiler reports an error on the last line (marked by COMPILE ERROR) where I am assigning an instance of SimpleTrain to a protocol type that it (in my best judgement) conforms to. How can I make it compile? What am I doing wrong? Or is this compiler issue?

protocol Train {
    typealias CarriageType

    func addCarriage(carriage: CarriageType)
    func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType
}

class SimpleTrain<T> : Train {
    typealias CarriageType = T
    private var carriages: [T] = [T]()

    func addCarriage(carriage: T) {
       carriages.append(carriage)
    }

    func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType {
        let short = SimpleTrain<T>()
        short.addCarriage(carriages[0])
        return short //COMPILE ERROR: SimpleTrain<T> is not convertible to 'ShortType'
    }
}


EDIT: Even when I explicitly downcast the shortTrain's return type above (so that last line of code snippet above reads return short as ShortType) as suggested by Antonio there is still compilation error when calling function shortTrain:

let s = SimpleTrain<String>()
s.addCarriage("Carriage 1")
s.addCarriage("Carriage 2")

let a = s.shortTrain() //ERROR: Cannot convert the expression's type '()' to type 'Train'
let b = s.shortTrain<SimpleTrain<String>>() //ERROR: cannot explicitly specialize a generic function

解决方案

First, you want to read the canonical thread on this from devforums. You particularly want to skip around to read jckarter's comments.

Now to the edited question:

let a = s.shortTrain() //ERROR: Cannot convert the expression's type '()' to type 'Train'

This is because you haven't given the compiler enough information to determine the type of a. Think through what it sees:

func shortTrain<ShortType: Train where ShortType.CarriageType == CarriageType>() -> ShortType {
let a = s.shortTrain()

The compiler needs to figure out the type of a at compile time, and it can't handle abstract types. It needs a fully specified type for ShortType (everything nailed down; all the generics specified, all the type aliases resolved). It looks around, and it sees some constraints on ShortType, but it doesn't see anything that actually gives a type. All it has is a, which isn't giving it any hints.

So unfortunately, that leaves you having to tell it explicitly what you want to happen.

let a: SimpleTrain<String> = s.shortTrain()

That's probably the opposite of what you were going for, but it's about all you can do in Swift right now. The Swift team has indicated (many times) that they are well aware of these issues with associated types (and several other related weaknesses in the type system). They're specifically aware of the Scala type system which can handle these things and has a lot in common with the current Swift type system (though in my experience, getting complex path-dependent associated types to work in Scala can also lead to hair tearing).

That said, it's not exactly obvious from your example what you planned to do with this functionality. Would some Trains return a different type as their shortTrain()?

I find that these problems often blow up in the general case, but tend to be quite solvable in the specific cases for the app in front of you. It's hard to build really arbitrary types in Swift in code that could solve every problem, but it often works out when you focus on the types you'll really need. For example, if shortTrain() returned Self, this obviously gets simpler. If the caller knows the desired resulting type, then an init(shorten:) can probably handle it. A protocol method like shortCarriages() -> [CarriageType] may provide a good bridge. Stay flexible on your design, and one of them will almost certainly work out.

这篇关于无法将类实例分配给其协议类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆