2017-01-31 57 views
2

我尝试过各种东西,做一些很简单的,我会做在Java中使用一个装饰图案,但希望在斯卡拉与可堆叠修改做失败了。完整性检查的特质

这是我用例:我实现一些简单的自动完成者。它们都实现基本特征:

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),在特征中方法之外的任何代码都会立即执行。

我怎么能执行,在施工时间我的理智检查,覆盖后,并没有失去作为一个可堆叠修改属性?

回答

2

当你override val MaxRetries = 5,您创建仅在匿名类的构造函数初始化的字段。构造函数的流程是这样的:

<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)来代替。

+0

看来你的回答是正确的,但你的方式,我认为解释仍不清楚。我不确切知道你在描述这个流程的代码(虽然我想你只是在谈论我的代码段,只是你在特质的身体中移动了理智检查),而你的意思是“anon”。 。你能否澄清这两点? – Dici

+0

使用'lazy val'来避免重新计算更为标准(尽管在文字的特定情况下,'def'会更好)。 –

+0

@AlexeyRomanov我实际上试过在特质声明中使用'lazy',它没有编译,但我意识到我应该在特性的具体用法中使用它。这能解决问题吗(现在不能尝试)?如果是这样,你能否在这种情况下添加一个描述初始化顺序规则的答案? – Dici