[解決済み】Scalaのvarとvalの定義の違いは何ですか?
質問
とはどのような違いがあるのでしょうか?
var
と
val
の定義と、なぜその両方が必要なのか? なぜ
val
の上に
var
その逆は?
どのように解決するのですか?
他の多くの方がおっしゃっているように、オブジェクトに割り当てられた
val
を置き換えることはできません。
var
ができます。ただし、当該オブジェクトは内部状態を変更される可能性があります。例えば
class A(n: Int) {
var value = n
}
class B(n: Int) {
val value = new A(n)
}
object Test {
def main(args: Array[String]) {
val x = new B(5)
x = new B(6) // Doesn't work, because I can't replace the object created on the line above with this new one.
x.value = new A(6) // Doesn't work, because I can't replace the object assigned to B.value for a new one.
x.value.value = 6 // Works, because A.value can receive a new object.
}
}
に割り当てられたオブジェクトを変更することはできません。
x
しかし、そのオブジェクトの状態を変更することは可能です。ところが、その根底にあるのは
var
.
さて、不変性というのは、いろいろな意味で良いことです。まず、オブジェクトが内部状態を変更しないのであれば、コードの他の部分がそれを変更していても心配する必要はありません。例えば
x = new B(0)
f(x)
if (x.value.value == 0)
println("f didn't do anything to x")
else
println("f did something to x")
これは、マルチスレッドシステムで特に重要になる。マルチスレッドシステムでは、以下のようなことが起こり得ます。
x = new B(1)
f(x)
if (x.value.value == 1) {
print(x.value.value) // Can be different than 1!
}
を使用する場合
val
を排他的に使用し、イミュータブルなデータ構造のみを使用する(つまり、配列を避け、すべて
scala.collection.mutable
など)、このようなことは起こらないので安心してください。つまり、リフレクションのトリックを行うコード、おそらくフレームワークがない限り、リフレクションは "immutable"値を変更することができます、残念なことに。
それも理由のひとつですが、もうひとつ理由があります。それは
var
を再利用したくなることがあります。
var
を複数の目的で使用することができます。これには、いくつかの問題があります。
- コードを読む人が、ある部分の変数の値が何であるかを知ることが難しくなる。
- あるコードパスで変数を再初期化するのを忘れてしまい、コードの下流に間違った値を渡してしまう可能性があります。
簡単に言うと
val
の方が安全で、より読みやすいコードになります。
では、その逆はどうでしょう。もし
val
はその方が良いのに、なぜ
var
ということです。しかし、ミュータビリティがパフォーマンスを大幅に向上させるという状況もあります。
例えば、イミュータブルな
Queue
. どちらか一方が
enqueue
または
dequeue
のようなものが入っている場合、新しい
Queue
オブジェクトを作成します。では、その中のすべての項目をどのように処理するのでしょうか?
例を挙げて説明します。例えば、数字が並んだキューがあり、その中から数字を合成したいとします。例えば、2、1、3の順で並んでいるキューがあったとして、213という数字を取り出したいんだ。まず、それを
mutable.Queue
:
def toNum(q: scala.collection.mutable.Queue[Int]) = {
var num = 0
while (!q.isEmpty) {
num *= 10
num += q.dequeue
}
num
}
このコードは高速で理解しやすい。その主な欠点は,渡されるキューが
toNum
そのため、あらかじめコピーを取っておく必要があります。このようなオブジェクト管理から解放されるのが不変性である。
今度は、これを
immutable.Queue
:
def toNum(q: scala.collection.immutable.Queue[Int]) = {
def recurse(qr: scala.collection.immutable.Queue[Int], num: Int): Int = {
if (qr.isEmpty)
num
else {
val (digit, newQ) = qr.dequeue
recurse(newQ, num * 10 + digit)
}
}
recurse(q, 0)
}
なぜなら、ある変数を再利用して私の
num
前の例のように、再帰に頼らざるを得ない。この場合、再帰は末尾再帰であり、かなり良い性能を持っている。しかし、常にそうとは限りません。時には、良い(読みやすく、単純な)末尾再帰の解決策がないこともあります。
しかし、このコードを書き換えて
immutable.Queue
と
var
を同時に使用することができます。例えば
def toNum(q: scala.collection.immutable.Queue[Int]) = {
var qr = q
var num = 0
while (!qr.isEmpty) {
val (digit, newQ) = qr.dequeue
num *= 10
num += digit
qr = newQ
}
num
}
このコードは依然として効率的で、再帰を必要とせず、キューをコピーしてから
toNum
. もちろん、変数を他の目的で再利用することは避けていますし、この関数の外のコードは変数を見ませんので、明示的にそうする場合を除いて、行ごとに値が変わることを心配する必要はないでしょう。
Scalaは、プログラマが最適な解決策と判断した場合、プログラマにそれをさせることを選択したのです。他の言語では、そのようなコードを難しくすることを選んでいます。Scalaは(そしてミュータビリティが広く普及している他の言語も)、その代償として、コンパイラがコードを最適化するための余地をあまり持たなくなりました。それに対するJavaの答えは、ランタイムプロファイルに基づいてコードを最適化することです。それぞれの長所と短所について、もっと詳しく説明することができます。
個人的には、Scalaは今のところ正しいバランスを保っていると思います。完璧とは言い難いですが。どちらも クロジュール と ハスケル は、Scalaが採用していない非常に興味深い概念がありますが、Scalaにも独自の強みがあります。今後、何が出てくるかはお楽しみです。
関連
-
[解決済み] Scala forallの例?
-
[解決済み] ScalaのSeqへのアペンド
-
[解決済み] Scala : valへの再割り当て [重複].
-
[解決済み] Scalaのオブジェクトとクラスの違い
-
[解決済み] Scalaのcase classとclassの違いは何ですか?
-
[解決済み】Scalaにおける中括弧と括弧の正式な違い、また、どのような場合に使用すべきなのか?
-
[解決済み】関数を定義する "def "と "val "の違いとは?
-
[解決済み】Scalaのコンテキストとビューバウンドとは何ですか?
-
[解決済み】ScalaのJavaConvertersとJavaConversionsの違いは何ですか?
-
[解決済み] Scalaの==と.equalsの違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】scalacコンパイルで "object apache is not a member of package org "と表示される。
-
[解決済み] SparkはYarnクラスタ上で動作しています exitCode=13:
-
[解決済み] 実行時に変数の型を取得したい
-
[解決済み] Scalaの変数の表示形式
-
[解決済み] sbtのlibraryDependenciesで言うところの++=と+=の違いは何ですか?
-
[解決済み] TimeoutExceptionが発生した場合、どのような原因が考えられるでしょうか。Sparkで作業しているときに[n秒]後にFuturesがタイムアウトしました[重複]。
-
[解決済み] SparkSQL - パーケットファイルを直接読み込む
-
[解決済み】Scalaのvarとvalの定義の違いは何ですか?
-
[解決済み] 型の論理和(ユニオン型)はどのように定義するのですか?
-
[解決済み] scalaのArrayとListの違いについて