Я пробовал разные вещи, чтобы сделать что-то довольно простое, что я бы сделал, используя шаблон декоратора на Java, но хотел сделать с помощью стековых изменений в Scala и не удалось.Проверка работоспособности абстрактного значения val в черте
Вот мой прецедент: Я внедряю некоторые простые автодоставки. Они все реализовать базовую черту:
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
).
Как я могу выполнить проверку работоспособности во время строительства, после переопределения и не теряя свойство быть штабелируемой модификацией?
Кажется, что ваш ответ правильный, но способ, которым вы его создавали, я думаю, что объяснение остается неясным. Я точно не знаю, для какого кода вы описываете этот поток (хотя, я думаю, вы говорите о моем фрагменте, за исключением того, что вы перемещаете проверку работоспособности в теле объекта), и что вы подразумеваете под «anon». , Не могли бы вы прояснить эти два вопроса? – Dici
Это более стандартно использовать 'lazy val', чтобы избежать перерасчета (хотя в конкретном случае литерала' def' будет лучше). –
@AlexeyRomanov Я действительно пробовал использовать 'lazy' в декларации признаков и не компилировался, но я понимаю, что должен был использовать его в конкретном использовании признака. Будет ли это исправлять проблему (не можете попробовать прямо сейчас)? Если да, не могли бы вы добавить ответ, описывающий правила порядка инициализации в этом контексте? – Dici