我试图创建一个通用的构建器隐式类型类,用于基于生成器的测试,作为学习练习。以下示例捕获了基本逻辑。 (而不是组合FooLike类型的成员,GenBuilder将用于组合scalacheck的Gen特征成员)
object Foo {
trait FooLike[A] {
def foo(a: A): String
}
object FooLike {
implicit object FooLikeInt extends FooLike[Int] {
override def foo(a: Int): String = a.toString
}
}
implicit class GenBuilder[T](self: T)(implicit f: FooLike[T]){
private var _items = Set(self)
def |?|(that: GenBuilder[T]): GenBuilder[T] = {
_items = _items + that.self
this
}
def items: Set[String] = _items.toSet.map((a: T) => f.foo(a))
}
}
object Test {
import Foo._
import Foo.FooLike._
def test = {
val res = 11 |?| 12 |?| 13 |?| 14
println(res.items)
}
}
Test.test
导致以下编译错误:
/Users/pkinsky/genBuilder.scala:19: error: value self is not a member of Main.$anon.Foo.GenBuilder[T]
_items = _items + that.self
这些编译器错误让我感到困惑:自己怎么不能成为GenBuilder [T]的成员?
(注意:我使用' scala $ filename'将其作为脚本运行,如果这对Scala的类型系统voodoo有任何影响)
答案 0 :(得分:1)
这不是某种深层类型系统voodoo 的情况,而是Scala中使用构造函数参数的不同方式。
将班级标题更改为
implicit class GenBuilder[T](val self: T)(implicit f: FooLike[T]){
(注意 val self)会使self
成为GenBuilder
的字段,而不仅仅是在constuctor / private中可用。
案例类使用它们的所有参数自动执行此操作。
答案 1 :(得分:0)
以下代码以某种方式工作。将that.self
替换为that.getSelf
def getSelf: T = self
会导致其编译和工作,按预期打印Set(11, 12, 13, 14)
。即将推出:我的下一个问题,我问为什么?为什么这样做?
object Foo {
trait FooLike[A] {
def foo(a: A): String
}
object FooLike {
implicit object FooLikeInt extends FooLike[Int] {
override def foo(a: Int): String = a.toString
}
}
implicit class GenBuilder[T](self: T)(implicit f: FooLike[T]){
private var _items = Set(self)
def getSelf: T = self
def |?|(that: GenBuilder[T]): GenBuilder[T] = {
that.getSelf
_items = _items + that.getSelf
this
}
def items: Set[String] = _items.toSet.map((a: T) => f.foo(a))
}
}
object Test {
import Foo._
import Foo.FooLike._
def test = {
val res = 11 |?| 12 |?| 13 |?| 14
println(res.items)
}
}
Test.test