对特征中抽象值的完整性检查
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
被覆盖之前(独立于它是否被声明为 val
或 def
).
我如何在构造时、覆盖后执行健全性检查,并且不会失去作为可堆叠修改的 属性?
当您 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
)代替。
我尝试了各种方法来做一些非常简单的事情,这些事情我会在 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
被覆盖之前(独立于它是否被声明为 val
或 def
).
我如何在构造时、覆盖后执行健全性检查,并且不会失去作为可堆叠修改的 属性?
当您 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
)代替。