在Scala中提供typeclass实例时,使用VAL或object是否更好

在Scala中提供typeclass实例时,使用VAL或object是否更好,scala,typeclass,implicit,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[B

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或隐式对象似乎没有太大变化


有区别吗?一种方法优于另一种方法吗?

使用
val x=new x{}
可以创建
x
的匿名子类,而使用
object x extends x
可以创建“适当”的子类。我认为
对象的开销是最小的,正如@applicius所指出的,它有一个合适的名称。因此,在这种情况下,我建议选择
对象。

val
对象
之间实际上有不止一个类型名

您知道,Scala中的
object
有点像Java中的单例。
也许您认为
string
BooleanShow
都在
对象中,而不是
类中,所以它们没有区别,但事实并非如此

它们是
val
object
,无论发生什么情况

在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
    }
}
scala> Show
!! Show created
!! string created
res0: Show.type = Show$@35afff3b
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$@18e419c5
如果只完成了定义,那么之后不会执行
println
s,因为
Show
实际上是一个单例。它还没有创建

接下来,在Scala REPL中执行
Show

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
    }
}
scala> Show
!! Show created
!! string created
res0: Show.type = Show$@35afff3b
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$@18e419c5
您可以看到,
Show
Show.string
中的
println
s被调用,但是
Show.BooleanShow
中的那个没有被调用

您可以在Scala REPL中执行
Show.BooleanShow
next

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
    }
}
scala> Show
!! Show created
!! string created
res0: Show.type = Show$@35afff3b
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$@18e419c5
Show.BooleanShow
最后被初始化。它是一个单身汉,所以它是懒惰的

基本上,您的问题与相同,只是您的
val
object
是在
对象中定义的,但是链接的问题试图找出
val
object
类中定义的差异,并且
val
中的方法使用反射(但您的使用重写,因此不涉及反射)。
隐式
基本上不会对它们的内容产生影响


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

因为他们说隐式总是使用显式类型,所以更喜欢val而不是object

比较不同之处

如果必要的话,让它变懒

阐述:

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
scala>trait T
定义性状T
scala>对象X{隐式[T];对象O扩展T}
:8:错误:找不到参数e:T的隐式值
对象X{隐式[T];对象O扩展T}
^
scala>对象X{隐式[T];隐式对象O扩展T}
:8:错误:找不到参数e:T的隐式值
对象X{隐式[T];隐式对象O扩展T}
^
scala>objectx{隐式[O.type];隐式objecto扩展T}
定义对象X
scala>对象X{隐式[T];隐式对象O扩展T;隐式定义y=O}
:8:错误:找不到参数e:T的隐式值
对象X{隐式[T];隐式对象O扩展T;隐式定义y=O}
^
scala>对象X{隐式[T];隐式对象O扩展T;隐式定义y:T=O}
定义对象X

O
的推断类型是singleton类型
O.type

一个区别是在异常堆栈跟踪中,以防涉及typeclass。在
对象的情况下,名称会更清晰。@applicius我觉得这是值得回答的。当然,我还想知道是否还有其他区别e可以想到。您的代码段中有一个输入错误。它应该是
implicit val
,而不是
val implicit
@bmaderbacher thx!已修复。除了使用
val
匿名类以及堆栈跟踪中的可读性问题之外,我看不到任何其他错误。您能详细说明一下为什么val是opp的显式类型吗是否对对象关闭?@欠准确。