我是疯了还是不应该快速编写代码?
protocol Protocol {
typealias Thing
}
class Class<X>: Protocol {
typealias Thing = X
}
func test<X:Protocol where X.Thing == Int> () -> X {
return Class<Int>() // error: cannot convert return expression of type 'Class<Int>' to return type 'X'
}
即使泛型类型和aliastype匹配,我似乎也无法将对象转换为其协议。
修改
我通过从现有代码中提取逻辑来提出上述代码,以简化问题。这样做我犯了一些错误。这是一个更新的(并且希望不那么令人困惑)代码示例:
protocol Protocol {
typealias Thing
}
class Class<X>: Protocol {
typealias Thing = X
}
func test<Y: Protocol where Y.Thing == Int> () -> Y {
return Class<Y.Thing>()
}
我希望编译器允许test()编译,结果类型为Protocol<Int>
。
答案 0 :(得分:6)
今天的Swift你的回归类型是不可能的。具有关联类型(PAT)的协议是抽象的。应用where子句不会改变它。请考虑以下代码:
let x: <WHAT-GOES-HERE?> = test()
x
会在哪种类型?没有什么可以写在那里编译。 x.Type
会返回什么?你想要的是Protocol where Protocol.Thing == Int
,但这不是Swift中的类型。它是一种约束。这是今天可以使用PAT的唯一方法。这就是为什么你不能拥有CollectionType<Int>
类型的属性,以及为什么你不能编写test()
函数。
该解决方案是一种类型擦除器,可将您的协议转换为具体的结构。例如:
protocol Protocol {
typealias Thing
func dosomething() -> Thing?
}
class Class<X>: Protocol {
typealias Thing = X
func dosomething() -> Thing? {
return nil
}
}
struct AnyProtocol<Thing> {
var _dosomething: () -> Thing?
func dosomething() -> Thing? {
return _dosomething()
}
}
func test() -> AnyProtocol<Int> {
return AnyProtocol(_dosomething: Class<Int>().dosomething)
}
Swift的某些未来版本可能会为您自动生成这些类型的橡皮擦,但我不知道任何具体的Swift-evolution建议,所以我们今天必须手工编写它们。
有关构建和使用类型橡皮的更多信息,请参阅A Little Respect for AnySequence。
答案 1 :(得分:1)
我是疯了还是不应该快速编写代码?
你可能会疯了,但我不会在这里使用你的代码作为测试。但是,代码没有任何意义,所以编译器是正确的抱怨。这对我来说也没有任何意义,所以即使对于一个人来说猜测你的意思也有点困难,但也许你的意思是:
go get
但即使编译,我仍然看不到你得到了什么。首先,我看不出protocol Protocol {
typealias Thing
}
class Class<X>: Protocol {
typealias Thing = X
}
func test<Y:Protocol where Y.Thing == Int> () -> Class<Y> {
return Class<Y>()
}
中的Y
将如何通过实际代码解决。也许(从标题这里判断)问题是你期望泛型类型可以转换为其他泛型类型。他们不是。例如,给定Animal类及其子类Dog,您无法在test
和MyGeneric<Animal>
之间进行交换。
您的评论也没有意义:
我要做的是将
MyGeneric<Dog>
投射到Class<Int>
没有Protocol<Int>
这样的类型。只有专门化协议的协议的特定采用者,以便Thing是Int。
答案 2 :(得分:1)
失败的原因很简单:你不尊重你自己定义的细节。
当你使用泛型时,你有一个泛型类型(在这种情况下是X
),它不仅仅意味着“任何满足约束的东西”,而是“满足约束的特定东西”。
因此,如果您执行let foo: Class<Int> = test()
之类的操作,您的代码仍然可以正常运行。
但是如果你做了像
class AnotherClass<X>: Protocol {
typealias Thing = X
}
let bar: AnotherClass<Int> = test()
你清楚地看到上述原因是错误的。
这里的主要概念是,当你使用泛型时,你只能使用泛型给你的东西。在这种情况下,请仅使用X
和X.Thing
,即Int
。除此之外,除非您在Protocol
中添加了某些内容或在函数test
我现在看到更新后的问题。看看Rob Napier的回答,你想要的是Type Eraser。虽然我认为对存在主义类型的快速演化的讨论会带来这个特征吗?