在Scala中提供类型类的实例时,使用val或object是否更好?

时间:2014-08-26 21:54:12

标签: scala typeclass implicit

Scala中的类型类模式涉及定义特征,例如:

trait Show[T] {
    def show(obj: T): String
}

然后您可以定义此类型类的实例化:

object Show {
    implicit val string = new Show[String] {
        def show(obj: String): String = obj
    }
    implicit object BooleanShow extends Show[Boolean] {
        def show(obj: Boolean): String = obj.toString
    }
}

为伴随对象中的基本类型定义这些实例化的优点是,只要涉及类型类(大致),它们就会自动在范围内。

在功能上,它似乎将实例化定义为隐式val或隐式对象不会发生太大变化。

有区别吗?有一种方式比另一方好吗?

3 个答案:

答案 0 :(得分:1)

valobject之间实际上不仅仅是类型名称

你知道,Scala中的object就像Java中的单例一样 也许您认为stringBooleanShow都在object而不是class,所以它们没有区别,但事实并非如此。

无论如何,它们都是valobject

在Scala REPL中尝试此操作。

trait Show[T] {
    def show(obj: T): String
}

object Show {
    println("!! Show created")

    implicit val string = new Show[String] {
        println("!! string created")
        def show(obj: String): String = obj
    }

    implicit object BooleanShow extends Show[Boolean] {
        println("!!BooleanShow created")
        def show(obj: Boolean): String = obj.toString
    }
}

如果仅完成定义,则之后不会执行println,因为Show是一个有效的单例。它尚未创建。

接下来,在Scala REPL中执行Show

scala> Show
!! Show created
!! string created
res0: Show.type = Show$@35afff3b

您看到printlnShow中的Show.string被调用,但Show.BooleanShow中的Show.BooleanShow未被调用。{/ p>

您可以在Scala REPL中执行scala> Show.BooleanShow !!BooleanShow created res1: Show.BooleanShow.type = Show$BooleanShow$@18e419c5

Show.BooleanShow

val最后被初始化了。它是一个单身人士,所以它是懒惰

基本上,您的问题与val and object inside a scala class?相同,只是您在object中定义了objectval,但链接的问题试图找出差异{{ 1 {}和objectclass中定义,而val中的方法使用反射(但您的使用覆盖,因此不涉及反射)。 implicit基本上没有区别于它们。

我想您已经知道classobject之间的区别。更多信息可以在链接的问题中找到。

答案 1 :(得分:1)

因为他们总是使用显式类型来表示implicits,所以更喜欢val而不是object。

比较Why can't Scala find my typeclass instance defined implicitly in the companion object, when the typeclass is not in a dedicated source file?,它会有所作为。

必要时让它变得懒惰。

精化:

scala> trait T
defined trait T

scala> object X { implicitly[T] ; object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
       object X { implicitly[T] ; object O extends T }
                            ^

scala> object X { implicitly[T] ; implicit object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
       object X { implicitly[T] ; implicit object O extends T }
                            ^

scala> object X { implicitly[O.type] ; implicit object O extends T }
defined object X

scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
<console>:8: error: could not find implicit value for parameter e: T
       object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
                            ^

scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y: T = O }
defined object X

O的推断类型是单例类型O.type

答案 2 :(得分:0)

使用val x = new X { }创建X的匿名子类,而使用object x extends X创建一个&#34;正确的&#34}。子类。我认为object的开销很小,而@applicius指出,它有正确的名称。因此,我建议在这种情况下使用object