REPL

时间:2016-03-10 16:27:55

标签: scala

我有代码定义特征的类型别名和该类型别名的单例对象。在尝试使用REPL中的这些时,我会遇到一些令人惊讶的错误。

这是我能够重现问题的最小代码量。请注意,将所有内容拆分为不同的文件非常重要,将所有内容放在一起似乎可以解决问题。

Decoder.scala

package foo

trait Decoder[E, D] {
  def decode(e: E): D
}

package.scala

package object foo {
  type StringDecoder[A] = Decoder[String, A]
}

StringDecoder.scala

package foo

object StringDecoder {
  def apply[A](f: String => A): StringDecoder[A] = new StringDecoder[A] { override def decode(s: String) = f(s) }

  def apply[A](implicit da: StringDecoder[A]): StringDecoder[A] = da

  def foobar: Unit = println("foobar")
}

以下是展示问题的示例REPL会话:

scala> import foo._
import foo._

scala> implicit val test: StringDecoder[Float] = StringDecoder(_.toFloat)
test: foo.StringDecoder[Float] = foo.StringDecoder$$anon$1@40a4337a

scala> StringDecoder.foobar
<console>:15: error: value foobar is not a member of object foo.StringDecoder
       StringDecoder.foobar

另一方面,如果我不首先引用类型别名,它可以正常工作:

scala> import foo._
import foo._

scala> StringDecoder.foobar
foobar

我目前的解释是,当前者在前者之前被引用时,对象在某种程度上被类型别名所遮蔽,但我真的想不出为什么会发生这种情况。我也没有在REPL之外(或tut之外,基本上是REPL)重现这个问题。

这种行为是否有任何已知的解释?

1 个答案:

答案 0 :(得分:4)

有没有已知的解释?不是,但这是一个已知问题(SI-7139)。

在关于该问题的评论中,Jason Zaugg提出了一种解决方法,这意味着将StringDecoder更改为类似的内容:

package foo

object StringDecoder0 {
  ...
}

然后:

package object foo {
  type StringDecoder[A] = Decoder[String, A]
  val StringDecoder: StringDecoder0.type = StringDecoder0
}

这不是一个正式的伴侣对,但它支持预期的用法(只要你没有在StringDecoder0中定义隐式实例)。