键入多态隐式类编译错误

时间:2014-06-22 18:24:19

标签: scala types typeclass implicit

我试图创建一个通用的构建器隐式类型类,用于基于生成器的测试,作为学习练习。以下示例捕获了基本逻辑。 (而不是组合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有任何影响)

2 个答案:

答案 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