假设我有两个类Input
和Output
,它们旨在相互连接。 Output
生成某种类型的值,Input
会消耗它们。
class Input[T] {
var output: Option[Output[_ <: T]] = None
}
class Output[T] {
var input: Option[Input[_ >: T]] = None
}
只要Input
和Output
对不能在相同类型的值上运行,只要Input
类型参数是Output
的超类型就可以了类型参数。请注意,两个类中的type参数都是不变的;在实际版本中,它用于共同和逆变位置。
我在其他地方有connect
方法,可在Input
/ Output
对之间建立链接:
def connect[T](output: Output[T], input: Input[_ >: T]) = {
output.input = Some(input)
input.output = Some(output)
}
如果我按如下方式调用此方法,则会出现类型错误:
val out = new Output[String]
val in = new Input[AnyRef]
connect(out, in)
错误是:
test.scala:17: error: type mismatch;
found : Output[String]
required: Output[AnyRef]
connect(out, in)
^
我可以通过写出类型参数来解决这个问题(在这种情况下,我会编写connect[String]
,但我认为编译器应该能够解决这个问题。如何更改{{1方法,以便自动推断类型参数?
修改:目前,我已将connect
作为connect
的方法,因此它会自动获取类型参数。这也有额外的好处,我可以使用中缀符号Output
,但设计感觉有点尴尬。
我仍然对编译器出现这种行为的原因感兴趣。我觉得它应该能够推断出类型参数。这实际上是按指定的方式工作吗?
答案 0 :(得分:6)
如果使用多个参数列表,有时会得到更好的结果:
def connect[T](output: Output[T])(input: Input[_ >: T]) = {
output.input = Some(input)
input.output = Some(output)
}
connect(out)(in)
......在这种情况下,确实有效。
答案 1 :(得分:0)
我可能完全错了,但我认为问题在于你将输入和输出联系起来: 输入的输出限制为T的子类型,但输出的输入限制为超类型T,唯一能满足这两个条件的类型是T.
Input[T] -> Output[ _ <: T ]
Output[Q] -> Input[ _ >: Q ]
使用输出创建输入(用_&lt;:T替换Q)时,您得到:
Input[T]->Input[ _ >: [_ <: T] ]
与
相同输入[T] - &gt;输入[_&lt ;: T&lt;:_]
因此类型不匹配
答案 2 :(得分:0)
实际上scala类型inferene现在无法处理“递归”。因此,如果参数的类型只能在与其他参数的搭配中进行推理,则scala无法推断。但是如果您使用不同的参数列表,则scala f(a)(b)(c,d)
将按列表推断类型,因此它通常可以更好地工作。
PS它过于简单了,但可以为你提供一些线索。