如何使用Scala的单例对象类型?

时间:2010-11-30 15:56:02

标签: scala types object singleton

我正在编写一个类,它作为一系列单例对象的基类。在每个单例对象中,都会有代表某些属性的val,我想编写一个方法,对于每个单例对象,只接受由它创建的对象。

所以我有以下内容:

class Obj[M <: Maker]

class Maker {
  implicit val me: this.type = this
  def make[M <: Maker](implicit maker: M) = new Obj[M]
  def accept(obj: Obj[this.type]) = {...}
}

到目前为止,这么好。然后我想声明其中一个单例对象:

object M extends Maker {
  val a = make
}

但是,如果我试试这个:

M.accept(M.a)

然后我收到编译时错误:

type mismatch; found : com.test.Obj[object com.test.M] required: com.test.Obj[com.test.M.type]

我的问题:

  1. 类型object com.test.M是什么类型,与com.test.M.type有什么不同?
  2. 我怎样才能更聪明地做到这一点?

4 个答案:

答案 0 :(得分:16)

与时俱进,我的好人!我在24小时前解决了这个问题。接下来,我希望看到速龙战斗机追逐渡渡鸟,疯狂地打开他们的马车鞭子,同时查看他们的点播屏幕上的股票报价。

有问题的提交是:http://lampsvn.epfl.ch/trac/scala/changeset/23622

// 1130.scala
class Obj[M <: Maker]

class Maker {
  implicit val me: this.type = this
  def make[M <: Maker](implicit maker: M) = new Obj[M]
  def accept(obj: Obj[this.type]) = ()
}

object M extends Maker {
  val a = make
}

object Test {
  def main(args: Array[String]): Unit = {
    M.accept(M.a)
  }
}

// too old
% /scala/inst/scala-2.9.0.r23619/bin/scalac ./1130.scala 
./1130.scala:15: error: type mismatch;
 found   : Obj[object M]
 required: Obj[M.type]
    M.accept(M.a)
               ^
one error found

// fresh enough
% /scala/inst/scala-2.9.0.r23624/bin/scalac ./1130.scala 
%

答案 1 :(得分:8)

使用this.type代替M。这个简化的例子应该有效:

class Obj[M <: Maker]

class Maker {
  def make() = new Obj[this.type]
  def accept(obj: Obj[this.type]) = println(obj)
}

object M extends Maker

object N extends Maker

M.accept(M.make()) //works!
M.accept(N.make()) //error! type mismatch!

答案 2 :(得分:3)

您的第一个问题,“object com.test.M的类型是什么,以及它与com.test.M.type的区别?”仍然没有得到回答。我没有在规范中找到它,但似乎object M类型是表示在定义对象M时隐式创建的类的内部类型。当然,M是该类的唯一实例,因此可以期望object M类型等同于M.type,但编译器显然不会这样看。

您遇到的问题({3}}是,当您调用M.type方法时,不会为type参数推断单例类型make。出于同样的原因,在下面的会话中推断出String而不是v.type

scala> val v = "asdf"                      
v: java.lang.String = asdf

scala> identity(v)
res0: java.lang.String  = asdf

其中identity定义为

def identity[T](v: T) = v

答案 3 :(得分:2)

这有效:

class Obj[M <: Maker]

class Maker {
  implicit val me: this.type = this
  def make[M <: Maker](implicit maker: M) = new Obj[M]
  def accept(obj: Obj[this.type]) = ()
}

object M extends Maker {
  val a = make[M.type]
}

M.accept(M.a)

秘密“酱”在单例对象中使用make[M.type]

@retronym值得称赞:How to correctly type-annotate this HList?