我希望能够使用this.type来定义一个创建不可变case类的新实例的方法。像这样:
trait Expression
{
def left : Expression
def right : Expression
def new_with_changes(l : Expression, r : Expression) : this.type
}
case class Derived(left : Expression, right : Expression)
{
def new_with_changes(l : Expression, r : Expression) : this.type =
{
new Derived(left, right)
}
}
不幸的是,编译器抱怨
test.scala:13: error: type mismatch;
found : Derived
required: Derived.this.type
new Derived(left, right)
^
one error found
为什么新案例类与this.type不匹配?
如果我将this.type更改为Base.new_with_changes中的Base并且Derived.new_with_changes中的Derived可以正常工作,但似乎它错过了this.type的精确性。
编辑:问题的真正意图是为什么在Scala中没有一种等效的方式来声明down的调用者执行downcast,就像this.type那样,但是对于一般类型。我不认为这很容易,但它会很好。
答案 0 :(得分:9)
this.type是此特定实例的唯一类型。它是单例类型 - 与同一类的任何其他实例不同的类型。这工作
class Foo { def f : this.type = this}
但这不是
class Foo { def f : this.type = new Foo}
经常不需要this.type,但它可以用来表达一些不能表达的约束
例如,这里的Inner类表示每个实例的外部方法都将返回它所来自的特定外部实例。
scala> class Outer{ class Inner { def outer : Outer.this.type = Outer.this}; def f(x : Inner) = println("ok")}
defined class Outer
scala> val o1 = new Outer
o1: Outer = Outer@13c1b69
scala> val o2 = new Outer
o2: Outer = Outer@1a3f178
scala> val in1 = new o1.Inner
in1: o1.Inner = Outer$Inner@627b5c
scala> val in2 = new o2.Inner
in2: o2.Inner = Outer$Inner@158c3b7
scala> val o3 = in1.outer
o3: o1.type = Outer@13c1b69
scala> o1.f(new o3.Inner)
ok
scala> o1.f(new o2.Inner)
<console>:8: error: type mismatch;
found : o2.Inner
required: o1.Inner
o1.f(new o2.Inner)
本文有另一个很好的例子,使用this.type来启用跨子类边界的方法链接:http://scalada.blogspot.com/2008/02/thistype-for-chaining-method-calls.html
scala> class A { def method1: this.type = this }
defined class A
scala> class B extends A { def method2: this.type = this }
defined class B
scala> val b = new B
b: B = B@15cb235
scala> b.method1.method2
res3: b.type = B@15cb235
答案 1 :(得分:7)
[注意:我不建议你这样做。]你很有可能完成你想要的。对this.type的转换是谎言,但是JVM不知道这个并且不能抛出异常,因为单例类型是scala概念。
现在如果您实际上在任何地方使用this.type的singleton属性,这将使您匆忙陷入困境。但是如果你想做的就是获得协变的返回类型而不用输入它们的麻烦,只有这个地方巨大的丑陋演员的小缺点:
trait Expression
{
def left : Expression
def right : Expression
def new_with_changes(l : Expression, r : Expression) : this.type
}
case class Derived1(left : Expression, right : Expression) extends Expression {
def new_with_changes(l : Expression, r : Expression) =
Derived1(left, right).asInstanceOf[this.type]
def foo() = "Derived1"
}
case class Derived2(left : Expression, right : Expression) extends Expression {
def new_with_changes(l : Expression, r : Expression) =
Derived2(left, right).asInstanceOf[this.type]
def bar() = "Derived2"
}
行动中:
scala> Derived1(Derived1(null,null), null)
res0: Derived1 = Derived1(Derived1(null,null),null)
scala> res0.new_with_changes(res0, null).bar
<console>:6: error: value bar is not a member of Derived1
res0.new_with_changes(res0, null).bar
^
scala> res0.new_with_changes(res0, null).foo
res2: java.lang.String = Derived1
scala> Derived2(Derived2(null, null), null)
res3: Derived2 = Derived2(Derived2(null,null),null)
scala> res3.new_with_changes(null, res3).foo
<console>:6: error: value foo is not a member of Derived2
res3.new_with_changes(null, res3).foo
^
scala> res3.new_with_changes(null, res3).bar
res6: java.lang.String = Derived2