为什么光滑表中的列是 defs 而不是 vals?

Why columns in slick Tables are defs instead of vals?

In slick documentation table 中的列定义为 def

class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
  def name = column[String]("COF_NAME", O.PrimaryKey)
  def supID = column[Int]("SUP_ID")
  def price = column[Double]("PRICE")
  def sales = column[Int]("SALES", O.Default(0))
  def total = column[Int]("TOTAL", O.Default(0))
  def * = (name, supID, price, sales, total)
}

有没有理由不应该是这样的:

class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
  val name = column[String]("COF_NAME", O.PrimaryKey)
  val supID = column[Int]("SUP_ID")
  val price = column[Double]("PRICE")
  val sales = column[Int]("SALES", O.Default(0))
  val total = column[Int]("TOTAL", O.Default(0))
  val * = (name, supID, price, sales, total)
}

列似乎没有使用任何可以改变的东西。

简答: 初始化顺序。

长答案:

让我们收集一些事实:

1) 使用 vals 而不是 defs 大多数情况下是可行的(如果您在代码中将大部分 defs 更改为 vals 它将大部分时间表现正确 - 至少这对我来说是这样)

2) 大多数 Slick 代码示例使用 defs.

因此,如果发生错误,可能只会在某些(罕见的?)情况下发生。

Slick 本身的这部分代码可能会阐明一些信息(查看 if(tt == null) (class `RelationalProfile):

之后的注释
def column[C](n: String, options: ColumnOption[C]*)(implicit tt: TypedType[C]): Rep[C] = {
      if(tt == null) throw new NullPointerException(
        "implicit TypedType[C] for column[C] is null. "+
        "This may be an initialization order problem. "+
        "When using a MappedColumnType, you may want to change it from a val to a lazy val or def.")
      new Rep.TypedRep[C] {
        override def toNode =
          Select((tableTag match {
            case r: RefTag => r.path
            case _ => tableNode
          }), FieldSymbol(n)(options, tt)) :@ tt
        override def toString = (tableTag match {
          case r: RefTag => "(" + _tableName + " " + r.path + ")"
          case _ => _tableName
        }) + "." + n
      }
    }

如果您查看引入此更改的提交:https://github.com/slick/slick/commit/be2ff6513d46abc9a25c8752c2931a786d4c5ad6

你应该找到很好的解释(提交评论)。