对特征中抽象值的完整性检查

Sanity check on abstract val in a trait

我尝试了各种方法来做一些非常简单的事情,这些事情我会在 Java 中使用装饰器模式来做,但是我想在 Scala 中进行可堆叠修改但失败了。

这是我的用例:我正在实现一些简单的自动完成器。他们都实现了一个基本特征:

trait AutoCompleter {
  def topSuggestions(prefix: String): Iterator[String]
  def update(sentence: String*): Unit

  final def topSuggestions(prefix: String, n: Int): List[String] = topSuggestions(prefix).take(n).toList
}

其中一些是基于特里树的自定义实现的具体实现:

/**
  * This auto-completer learns from the user's input, and therefore does not require a preliminary dictionary.
  */
class ParrotAutoCompleter extends AutoCompleter {
  private val trie = new WeightedTrie[Char, String]()

  override def topSuggestions(prefix: String): Iterator[String] = trie.prefixedBy(prefix)
  override def update(sentence: String*): Unit = sentence.foreach(trie += _)
}

还有一些是可堆叠的修改:

/**
  * This auto-completer will try returning some suggestions when the prefix did not match any known word by dropping the
  * last character until it finds a suggestion
  */
trait TolerantAutoCompleter extends AutoCompleter {
  def MaxRetries: Int

  abstract override def topSuggestions(prefix: String): Iterator[String] = {
    if (MaxRetries < 1) throw new IllegalArgumentException("Should allow 1 retry minimum, but max retries was: " + MaxRetries)
    for (attempt <- 0 to Math.min(prefix.length, MaxRetries)) {
      val suggestions = super.topSuggestions(prefix.substring(0, prefix.length - attempt))
      if (suggestions.hasNext) return suggestions
    }
    Iterator()
  }
}

我是这样使用它们的:

val autoCompleter = new ParrotAutoCompleter with TolerantAutoCompleter { override val MaxRetries: Int = 5 }

这个实现工作正常,但它有一个缺陷:在 MaxRetries 上执行的健全性检查很晚才完成,只有在使用自动完成器时而不是在创建它时。更有趣的是,它每次都是 运行 而不是一次。

问题在于特征中方法之外的任何代码都会立即执行,甚至在 MaxRetries 被覆盖之前(独立于它是否被声明为 valdef).

我如何在构造时、覆盖后执行健全性检查,并且不会失去作为可堆叠修改的 属性?

当您 override val MaxRetries = 5 时,您创建了一个仅在匿名 class 的构造函数中初始化的字段。构造函数的流程是这样的:

<jvm>: Initialize MaxRetries field to 0
<anon>: call super
TolerantAutoCompleter: call super
...
TolerantAutoCompleter: sanity check MaxRetries (still 0!)
TolerantAutoCompleter: return
<anon>: set MaxRetries to 5
<anon>: return

使用

new ParrotAutoCompleter with TolerantAutoCompleter { override def MaxRetries = 5 }

(使用 def)代替。