【问题标题】:Scala: use def or val when instantiating from a trait?Scala:从特征实例化时使用 def 或 val?
【发布时间】:2026-01-23 08:40:01
【问题描述】:

我正在阅读 Chiusano 和 Bjarnason 的 Scala 中的函数式编程

在第 10 章中,他们定义了 Monoid 特征:

trait Monoid[A] {
    def op(a1: A, a2: A): A
    def zero: A
}

该特征的两个示例实例如下:

1) String Monoid:

val stringMonoid = new Monoid[String] {
    def op(a1: String, a2: String) = a1 + a2
    val zero = ""
}

2) List Monoid:

def listMonoid[A] = new Monoid[List[A]] {
    def op(a1: List[A], a2: List[A]) = a1 ++ a2
    val zero = Nil
}

我的问题是,为什么我们在stringMonoid 的情况下使用val,而在listMonoid 的情况下使用def

【问题讨论】:

  • listMonoid 采用类型参数 [A],而 val 不允许使用该类型参数(语法错误)。

标签: scala


【解决方案1】:

stringMonoid是字符串类型new Monoid[String]

listMonoid 是一个泛型类型new Monoid[List[A]]。为了传递这个泛型类型A,它被声明为def

def listMonoid[A] = new Monoid[List[A]]

编辑

解决评论:

如果您仍然希望将val 用于listMonoid,则定义其中包含的列表。

val listMonoid = new Monoid[List[Int]] {
  def op(a1: List[Int], a2: List[Int]) = a1 ++ a2
  def zero = List.empty
}

【讨论】:

  • 这是有道理的。那么使用listMonoid 的正确方法是什么?
  • @cwl listMonoid[String].zero 应该可以工作。最终,你可能会想要隐式,也许Simulacrum