如何使scala类型参数推断更智能?

时间:2015-01-26 20:01:18

标签: scala type-parameter generic-type-argument

我有一个函数,它接受的类型参数T必须是this.type的子类型:

def injectFrom[T <: this.type](same: T): Unit = ...

然而每次我使用它时,编译器都给了我一个

  

类型T无法推断“错误

每次都可以通过明确指定T (instance_variable).type来解决问题。我怎么能避免将来这样做?

3 个答案:

答案 0 :(得分:3)

this.type是一种单独的对象或类实例,而不是类。

在以下代码a1a2中将有不同的this.type

class A
val a1 = new A()
val a2 = new A()

因此,类型参数[T <: this.type]并不真正有意义,因为您无法extend object或实例。

如果你想要一个设计,那么子类中的函数只能接受那个子类的实例(以及因此只接受那个子类的子类的实例),你必须使用type参数或类型变量使类型显式化:

trait A {
    type Self
    def injectFrom(same: Self): Unit = ???
}
class B extends A {
    type Self = B
}
class C extends A {
    type Self = C
}

或Scala在Ordered实现中所做的事情:

trait A[Self] {
    def injectFrom(same: Self): Unit = ???
}
class B extends A[B]
class C extends A[C]

在这两种情况下,new B().injectFrom(new B())都会编译,但new B().injectFrom(new C())不会。

第二个示例的修改,允许您在this injectFrom thisA

trait A[Self] {
    def injectFrom(same: A[Self]): Unit = ???
    def test() {
        this injectFrom this
    }
}

答案 1 :(得分:0)

编译器坚决拒绝推断单例类型。

scala> class C { def f[A <: this.type](a: A) = ??? }
defined class C

scala> val c = new C
c: C = C@71f2a7d5

scala> c f c
<console>:10: error: inferred type arguments [C] do not conform to method f's type parameter bounds [A <: c.type]
              c f c
                ^
<console>:10: error: type mismatch;
 found   : C
 required: A
              c f c
                  ^

经典参考:

http://www.artima.com/pins1ed/modular-programming-using-objects.html#i-108236764-1

  

通常这些类型太具体而无用,这就是为什么   编译器不愿意自动插入它们。

答案 2 :(得分:0)

这样做你想要的吗?我不知道这是不是最好的方式,但是......

trait Foo {
  class Tag[U <: AnyRef](x: U) {
    type UT = U
  }
  val tag = new Tag(this)
  def injectFrom[T <: tag.UT](same: T): Unit = {
    println("Injected")
    ()
  }
}

class NotBar
{
}

class Bar extends Foo
{
  injectFrom(this)
  val notThis = new NotBar
  injectFrom(notThis)
}

结果:

x.scala:20: error: inferred type arguments [NotBar] do not conform to method injectFrom's type parameter bounds [T <: Bar.this.tag.UT]
  injectFrom(notThis)
  ^
x.scala:20: error: type mismatch;
 found   : NotBar
 required: T
  injectFrom(notThis)
             ^
two errors found

编辑:这可能不是你想要的,因为这将允许注入这个类的任何子类型,而不是从实例的特定子类型注入?