2016-06-23 4 views
1

ListBufferは効率的に要素を末尾に追加してからListに変換できます。ScalaのListBufferクラスの+ =メソッドのソースコードに関する初心者のパズル

私はListBufferの追加メソッドのソースコード(+=)を研究しましたが、その動作を理解することが難しいと感じました。詳細なソースコードはhereです。

抜粋ソースコード:else一部で

final class ListBuffer[A] extends AbstractBuffer[A] { 
    private var start: List[A] = Nil 
    private var last0: ::[A] = _ 
    private var exported: Boolean = false 
    private var len = 0 

    def += (x: A): this.type = { 
    if (exported) copy() 
    if (isEmpty) { 
     last0 = new :: (x, Nil) 
     start = last0 
    } else { 
     val last1 = last0  // last1 is a local variable, is it necessary here? 
     last0 = new :: (x, Nil) 
     last1.tl = last0  // 
    } 
    len += 1 
    this 
    } 
} 

、ローカル変数last1が定義され、その後終了時にいくつかの要素を含むように構成されています。 last0は常に最後のセルを指します。

ここにlast1が必要ですか?結局のところ、それはブロックの後に範囲外になります。私はなぜ著者がlast1をここで定義しなければならないのか理解できません。 last0常に最後「のポイント」を行う必要があります。この減少に問題があります除き、ここで何が起こっている

答えて

1

は、本質的に

last0.ti = new :: (x, Nil) // put new element x at end of list 

です。従ってlast1は、end-of-the-list.t1にアクセスすることができ、新しいリストの終わりを追加することができるように、リストの終わりへの一時的な参照になります。

0

だから3行あります。

last1は現在のlast0を指します。

last0が新しい最後の要素に設定されます。

last1.t1がlast0に設定されています。

last1は新しいオブジェクトではありません。現在の最後のものを指すだけです。 t1私は、その次の要素へのクラスポインタを想定しています。 これは、現在の最後の要素を新しい要素に向けることです。

これはscalableで可能な場合は避けられるmutablesとvarsを使用するので、scalaでは混乱する可能性があります。

2

まあ、

val last1 = last0  // last1 is a local variable, is it necessary here? 
    last0 = new :: (x, Nil) 
    last1.tl = last0  // 

あなたが見ることができるように、確かに私たちはlast0を変更した後.tlを変更するために使用されます。

次に、.tlは何ですか?

@SerialVersionUID(509929039250432923L) // value computed by serialver for 2.11.2, annotation added in 2.11.4 
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] { 
    override def tail : List[B] = tl 
    override def isEmpty: Boolean = false 
} 

あなたが見ることができるように、クラス::は本当に不変ではありません。まさに最後の行が何をするかで変更することができ、リストの残りの部分への参照があります。

last0を変更した後、なぜそれを変更する必要がありますか?これは、新しく作成された最後の要素を保持するために一時変数が必要なためです。とにかくlast0を代入する必要があります。つまり、last0を再割り当てして、最後の新しい要素を作成し、 last1で)。

希望します。

+0

ありがとうございました。まだ混乱している。なぜ "新しく作成された最後の要素を保持するために一時変数が必要"なのでしょうか? 'last0 = new ::(x、Nil)'は 'last0'のクラスフィールドに最後のセルを格納します。しかし、 'last1'は単なるローカル変数であり、' else'コードブロックの後に消えます。 – Spring

+0

'last0'を動かすだけでは不十分です。今作成したばかりの要素を指すように、最後から2番目の要素の 'tl'も必要です。だから 'last0.tl = new ::(x、Nil); last0 = last0.tl'は 'last1'の代わりに' tl'を使ってうまくいくでしょう。 2つの間の選択は、味覚および/または性能試験の問題である。 – alf

+0

この '+ ='メソッドの実装には問題があることがわかりました。追加された要素は 'start'リストに保存できませんでした。実行デモがあります:(1) 'val t = new ListBuffer [Int]'; (2) 't + = 1' // {' start = List(1) '、' last0 = List(1) '}; (3) 't + = 2 '; {'start = List(1)'、 'last0 = List(1)'}(4) 't.toList' {' List(1) '}です。 – Spring

関連する問題