【问题标题】:Type inference with type aliases and multiple parameter list function具有类型别名和多参数列表功能的类型推断
【发布时间】:2017-04-26 13:12:42
【问题描述】:

编译这段代码

case class MyType()
object TestMe extends App {
  type Fun[T] = T => Int
  def myFun[T](x: T): Int = ???
  def matcher[T](f: Fun[T])(p: T): Int = ???
  var f = myFun[MyType] _
  val p = MyType()
  matcher(f)(p)
}

失败并出现此错误:

Error:(16, 11) type mismatch;
 found   : ... MyType => Int
 required: ... TestMe.Fun[T]
    (which expands to)  T => Int
  matcher(f)(p)

如下修改代码即可解决问题:

case class MyType()
object TestMe extends App {
  type Fun[T] = T => Int
  def myFun[T](x: T): Int = ???
  def matcher[T](f: Fun[T])(p: T): Int = ???
  var f: Fun[MyType] = myFun[MyType] // <-- Explicit type
  val p = MyType()
  matcher(f)(p)
}

更改参数顺序也可以解决问题:

case class MyType()
object TestMe extends App {
  type Fun[T] = T => Int
  def myFun[T](x: T): Int = ???
  def matcher[T](p: T)(f: Fun[T]): Int = ??? // <-- Flipping the argument, so the first argument have explicitly the parametric type
  var f = myFun[MyType] _
  val p = MyType()
  matcher(p)(f)  // <-- Calls with flipped arguments
}

我的理解(我猜是因为我缺乏 Scala 知识)是“类型”只是创建类型别名,但看起来不像那样。 有人可以解释编译失败的原因吗?

谢谢

【问题讨论】:

    标签: scala


    【解决方案1】:

    这是类型推断以及类型器在编译时如何解析类型的限制。

    在 Scala 中,可以在参数列表之间(而不是在它们内部)推断类型。当您首先将T 类型的p 作为参数放在第一个参数列表中时,类型器可以先将T 绑定到MyType,然后第二个参数列表知道f 是@987654326 @因为它可以推断出T

    |-- matcher(p)(f) : pt=Unit EXPRmode (site: method main in Test)
    |    |    |    |    |-- matcher(p) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |    [adapt] [T](p: T)(f: Fun[T])Int adapted to [T](p: T)(f: Fun[T])Int
    |    |    |    |    |    |    \-> (p: T)(f: Fun[T])Int
    |    |    |    |    |    |-- p BYVALmode-EXPRmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |    \-> MyType
    |    |    |    |    |    solving for (T: ?T)
    |    |    |    |    |    \-> (f: Fun[MyType])Int
    |    |    |    |    |-- f : pt=Fun[MyType] BYVALmode-EXPRmode (site: method main in Test)
    |    |    |    |    |    \-> MyType => Int
    

    反过来也行不通,编译器无法从 MyType =&gt; Int 类型的函数推断出 TMyType(请记住,函数的参数类型也可能是逆变的):

    -- matcher(f)(p) : pt=Unit EXPRmode (site: method main in Test)
    |    |    |    |    |-- matcher(f) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |    [adapt] [T](f: Fun[T])(p: T)Int adapted to [T](f: Fun[T])(p: T)Int
    |    |    |    |    |    |    \-> (f: Fun[T])(p: T)Int
    |    |    |    |    |    |-- f : pt=Fun[?] BYVALmode-EXPRmode-POLYmode (silent: method main in Test)
    |    |    |    |    |    |    \-> MyType => Int
    |    |    |    |    |    solving for (T: ?T)
    |    |    |    |    |    [search #1] start `MyType => Int`, searching for adaptation to pt=(MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled
    |    |    |    |    |    [search #2] start `MyType => Int`, searching for adaptation to pt=(=> MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled
    

    正如您所指出的,切换参数列表是有效的。您还可以通过在 matcher 方法上声明类型来显式帮助编译器推断类型:

    matcher[MyType](f)(p)
    

    【讨论】:

      猜你喜欢
      • 2013-03-04
      • 2018-05-15
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多