【问题标题】:Why can't Scala infer the type parameter in this example?为什么 Scala 不能在这个例子中推断类型参数?
【发布时间】:2010-11-14 04:37:08
【问题描述】:

假设我有两个类,InputOutput,它们被设计为相互连接。 Output 产生某种类型的值,Input 消费它们。

class Input[T] {
  var output: Option[Output[_ <: T]] = None
}
class Output[T] {
  var input: Option[Input[_ >: T]] = None
}

只要Input 类型参数是Output 类型参数的超类型,如果InputOutput 对不在同一类型的值上操作,也可以。请注意,两个类中的类型参数是不变的;在实际版本中,它同时用于协变和逆变位置。

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


编辑:目前,我已经将connect 设为Output 的方法,因此它会自动获取类型参数。这还有一个额外的好处,我可以使用中缀符号out connect in,但是设计感觉有点别扭。

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

【问题讨论】:

  • 你的意思是“不要在上操作同一种值”
  • 你试过向 Scala 邮件列表提问吗?

标签: generics scala types type-inference


【解决方案1】:

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

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

connect(out)(in)

...在这种情况下,它确实有效。

【讨论】:

  • 你能详细说明这是为什么吗? “有时会得到更好的结果”听起来不太确定!
  • 遗憾的是,类型推断器没有指定,有时也不是确定性的。
【解决方案2】:

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

Input[T] -> Output[ _ <: T ]
Output[Q] -> Input[ _ >: Q ]

当您使用输出创建输入(将 Q 替换为 _ <: t>

Input[T]->Input[ _ >: [_ <: T] ]

输入[T]->输入[_<:t>

因此类型不匹配

【讨论】:

  • 在我的示例中,String 和 AnyRef 满足我的约束。输出产生字符串并需要一个消耗某种超类型字符串的输入。 Input 使用 AnyRefs 并需要一个 Output 来生成 AnyRef 的某个子类型。由于 String 是 AnyRef 的子类型,因此满足约束。
  • 问题是connect只有一个合适的类型参数,那就是Output的类型参数。当我明确指定它时,它工作正常。如果我不这样做,它会尝试使用 Input 的类型参数,并且在 Output 参数上出现类型错误。
  • 对不起,我看错了connect[T](的签名中的Input[_ >: T]
【解决方案3】:

实际上 scala 类型的 inferene 目前无法处理“递归”。因此,如果只能在与其他参数搭配时推断出参数类型,则 scala 无法推断。但是如果你使用不同的参数列表 scala f(a)(b)(c,d)会逐个列表推断类型,所以它通常效果更好。

PS 它过于简单,但可以为您提供一些线索。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    • 2011-03-19
    相关资源
    最近更新 更多