Generics 为什么可以';t Scala在本例中推断类型参数?

Generics 为什么可以';t Scala在本例中推断类型参数?,generics,scala,types,type-inference,Generics,Scala,Types,Type Inference,假设我有两个类,Input和Output,它们被设计为相互连接输出生成某种类型的值,而输入使用这些值 class Input[T] { var output: Option[Output[_ <: T]] = None } class Output[T] { var input: Option[Input[_ >: T]] = None } 如果按如下方式调用此方法,则会出现类型错误: val out = new Output[String] val in = new In

假设我有两个类,
Input
Output
,它们被设计为相互连接<代码>输出生成某种类型的值,而
输入
使用这些值

class Input[T] {
  var output: Option[Output[_ <: T]] = None
}
class Output[T] {
  var input: Option[Input[_ >: T]] = None
}
如果按如下方式调用此方法,则会出现类型错误:

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]
,但我认为编译器应该能够为我解决这个问题。我如何更改
connect
方法,以便自动推断类型参数


编辑:目前,我已经将
连接
作为
输出
的一种方法,因此它会自动获取类型参数。这还有一个额外的好处,我可以使用中缀符号
输出连接
,但设计感觉有点尴尬


我仍然对编译器为何表现出这种行为感兴趣。我觉得它应该能够推断类型参数。这是否真的按照指定的方式工作?

如果使用多个参数列表,有时会得到更好的结果:

def connect[T](output: Output[T])(input: Input[_ >: T]) = {
  output.input = Some(input)
  input.output = Some(output)
}

connect(out)(in)

…事实上,在这种情况下,它是有效的。

我可能完全错了,但我认为问题在于当你将输入和输出结合在一起时: 输入有一个限制为T的子类型的输出,但输出有一个限制为T的超类型的输入,唯一能满足这两个条件的类型是T

Input[T] -> Output[ _ <: T ]
Output[Q] -> Input[ _ >: Q ]
Input[T]->Output[\uu>输入[\u>:Q]

当你用输出来创建输入时(用输入来代替Q):[\uInput[\uP>实际上scala类型inferene现在不能处理“递归”。因此,如果参数类型只能与其他参数搭配推断,scala推理失败。但是如果你使用不同的参数列表scala
f(a)(b)(c,d)
将逐个列表推断类型,因此通常效果更好


PS这太简单了,但可以给你一些线索。

你的意思是“不要对同一种价值进行操作”你试过向Scala邮件列表提出这个问题吗?你能详细说明为什么吗?“有时会得到更好的结果”听起来不是很确定!遗憾的是,类型推断器没有规范,有时也不是确定的。在我的示例中,String和AnyRef满足我的约束。输出生成字符串,并需要一个使用某些超类型字符串的输入。输入使用AnyRef,并需要一个生成AnyRe子类型的输出f、 由于String是AnyRef的子类型,因此满足了约束条件。问题是,connect正好有一个合适的类型参数,这就是输出的类型参数。当我显式指定此参数时,它工作正常。如果我不指定,它将尝试使用输入的类型参数,并且在输出参数上出现类型错误t、 抱歉,我误读了connect[t]签名中的输入[\u>:t](
Input[T] -> Output[ _ <: T ]
Output[Q] -> Input[ _ >: Q ]
Input[T]->Input[ _ >: [_ <: T] ]