如何使 Scala 类型参数推断更智能?
How to make scala type parameter inference smarter?
我有一个函数接受类型参数 T
,它必须是 this.type
的子类型:
def injectFrom[T <: this.type](same: T): Unit = ...
然而每次我使用它时,编译器都会给我一个
type T cannot be inferred" error
并且每次都可以通过将 T
明确指定为 (instance_variable).type
来修复。我以后如何避免这样做?
编译器坚决拒绝推断单例类型。
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
Usually such types are too specific to be useful, which is why the
compiler is reluctant to insert them automatically.
这是否符合您的要求?我不知道这是不是最好的方法,但是...
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
编辑:这可能不是您要查找的内容,因为这将允许注入此 class 的任何子类型,而不是从实例的特定子类型注入?
this.type
是单个对象或 class 实例的类型,而不是 class.
在下面的代码中a1
和a2
会有不同的this.type
:
class A
val a1 = new A()
val a2 = new A()
所以类型参数 [T <: this.type]
没有意义,因为你不能 extend
一个 object
或一个实例。
如果你想有一个设计,让 subclasses 中的函数只能接受那个 subclass 的实例(因此 subclasses 的实例只能那个 subclass) 你必须通过使用类型参数或类型变量来明确类型:
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())
不会。
修改第二个例子,让你在A
里面有this injectFrom this
:
trait A[Self] {
def injectFrom(same: A[Self]): Unit = ???
def test() {
this injectFrom this
}
}
我有一个函数接受类型参数 T
,它必须是 this.type
的子类型:
def injectFrom[T <: this.type](same: T): Unit = ...
然而每次我使用它时,编译器都会给我一个
type T cannot be inferred" error
并且每次都可以通过将 T
明确指定为 (instance_variable).type
来修复。我以后如何避免这样做?
编译器坚决拒绝推断单例类型。
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
Usually such types are too specific to be useful, which is why the compiler is reluctant to insert them automatically.
这是否符合您的要求?我不知道这是不是最好的方法,但是...
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
编辑:这可能不是您要查找的内容,因为这将允许注入此 class 的任何子类型,而不是从实例的特定子类型注入?
this.type
是单个对象或 class 实例的类型,而不是 class.
在下面的代码中a1
和a2
会有不同的this.type
:
class A
val a1 = new A()
val a2 = new A()
所以类型参数 [T <: this.type]
没有意义,因为你不能 extend
一个 object
或一个实例。
如果你想有一个设计,让 subclasses 中的函数只能接受那个 subclass 的实例(因此 subclasses 的实例只能那个 subclass) 你必须通过使用类型参数或类型变量来明确类型:
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())
不会。
修改第二个例子,让你在A
里面有this injectFrom this
:
trait A[Self] {
def injectFrom(same: A[Self]): Unit = ???
def test() {
this injectFrom this
}
}