在Scala中提供typeclass实例时,使用VAL或object是否更好
Scala中的类型类模式涉及定义一个特征,例如:在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
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的显式类型吗是否对对象关闭?@欠准确。