90593


Kotlinの実装を眺めていて疑問があったので質問します。

<https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/src/kotlin/text/StringsJVM.kt#L803>

↑のコードの

[code]

    1 -> this[0].let { char -> String(CharArray(n) { char }) }
    
[/code]

は、

[code]

    1 -> String(CharArray(n) { this[0] })
    
[/code]

と書いても同じことのように思えます。単に好みの問題か、それとも`let`を使う書き方には何かメリットがあるのでしょうか。ご教示いただけると幸いです。


CC BY-SA 4.0
2022-08-15T11:58:43.763
90569
2022-08-17T11:49:21.020
50949
question
kotlin
Kotlinでletを使うことのメリット


なかなか興味深い話ですね。  
最近kotlinを使っていないので自信がありませんが、そんな浅い知識で思いついたことが一つ…。

kotlinの`Array`のイニシャライザの「`{}`」は、他の言語のような初期値ではなく、各要素に対して呼ばれる初期化関数です。  
「`CharArray(n) { this[0] }`」と書かれた場合、`this[0]`が`n`回参照されることになります。  
`CharArray`のイニシャライザの最中に、`this[0]`が「何らかの理由で」変更された場合、「同じ文字のリピート」ではなくなってしまいます。  
`let`関数を使えば、関数の引数という形で一旦別変数に格納されるので、`this[0]`が変更されても同じ文字のリピートになります。

…問題は、「何らかの理由」があるかどうか、なんですが、あえて言うなら別スレッドで変更されることがあるのかなぁ、と思いますが、もしかすると、「`let`を呼び出すだけだから、とりあえずやっとけ」程度の理由かもしれません。


CC BY-SA 4.0
2022-08-17T00:04:14.513
90588
2022-08-17T00:04:14.513
15473
90569
answer


まず: `this[0]` というコードは `this` が `CharSequence` であることから
[`CharSequence.get(Int)`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char-
sequence/get.html) に解決されます。

お示しになられたコードはJVM (Java仮想マシン。以下、JVM) をターゲットにしていると思われるので、以下JVMの話をします。[Java
8](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/CharSequence.html)
では、CharSequenceは以下のように定義されています。

> CharSequenceはchar値の読取り可能なシーケンスです。

[`let`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/let.html)
を用いることで、`let`のレシーバの値を「固定」することができます。すなわち、

[code]

    1 -> this[0].let { char -> String(CharArray(n) { char }) }
    
[/code]

は

[code]

    1 -> run {
        val __tmp = this[0] // 不可視の一時変数
        String(CharArray(n) { __tmp })
    }
    
[/code]

と同じことです ([`run`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run.html)
はテンポラリなスコープを実現するために使いました) 。

確かに、ご質問者様の言うとおり、`String` (JVMがターゲットですから、`java.lang.String`)
をレシーバにして呼び出された場合、`__tmp` を展開してしまっても変わりありません。`java.lang.String`
はイミュータブルであり、先頭の文字を変更するという芸当はできないため自動的にスレッドセーフになるからです。

しかし、これが
[`StringBuilder`](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/StringBuilder.html)
など、他の`CharSequence`を実装する型だと、「処理中に`this[0]`が変化しない」という前提を敷くことができないため、話が変わってくるものと思われます。実際、その前提は`StringBuilder`を他のスレッドから変更すると崩れてしまいます。


CC BY-SA 4.0
2022-08-17T11:49:21.020
90593
2022-08-17T11:49:21.020
44531
90569
answer