在类型 class 解决方案中遵循隐式实现有什么区别?

What is the difference in following implicit implementations in type class solutions?

在下面的例子中:

trait Writer[A] {
 def write(a: A): String
}

case class Person(name: String, age: Int)
case class Student(name: String, roll: Int)

object DefaultStringWriters {
//here is implicit object, when to use object here?

implicit object PersonNameWriter extends Writer[Person] {
  def write(person: Person) = person.name
 }

//here is implicit val, when to use val here?

implicit val studentNameWriter = new Writer[Student] {
  def write(student: Student) = student.name
 }
}

object WriterUtil {
 def stringify[A](data: A)(implicit writer: HtmlWriter[A]): String = {
  writer.write(data)
 }
}

#It works here with both.
WriterUtil.stringify(Person("john", "person@john.com"))
res0: String = john

WriterUtil.stringify(Person("student", "student@student.com"))
res1: String = student

在实际情况下我们什么时候使用隐式对象或 val?

差异

  1. val 是在对象初始化期间按指定顺序创建的。 object 是懒惰创建的。

  2. object 创建新的单例类型(例如 PersonNameWriter.typeval 创建无类型(如本例)或结构类型。

  3. val 可以被覆盖。 object 不能。

  4. val 可以赋给任何表达式,例如Foo()new Fooobject 必须是 class 定义,并且在重用代码的方式上受到更多限制,例如extends Foo.

如果您不关心这些差异中的任何一个,那么选择哪一个都没有关系。在那种情况下,我建议 val 因为它不需要任何同步。