8.6 Assignment Expressions

Last-modified: 2025-03-22 (土) 21:12:16

8.6 代入式

代入とは、変数に新しい値を格納する式です。たとえば、次の式は変数に値 1 を代入しますz。

z = 1

この式が実行されると、変数のz値は1になります。z代入前の古い値は忘れられます。'=' 記号は代入演算子と呼ばれます。
割り当てには文字列値も格納できます。たとえば、次の式は"this food is good"変数に値を格納しますmessage。

thing = "food"
predicate = "good"
message = [ "this " , thing , " is " , predicate ]
⇒ "this food is good"

(これは文字列の連結も示しています。)
ほとんどの演算子 (加算、連結など) は、値を計算する以外には効果がありません。値を無視する場合は、演算子を使用しないほうがよいでしょう。代入演算子は異なります。代入演算子は値を生成しますが、値を無視した場合でも、代入は変数の変更を通じて影響を及ぼします。これを副作用と呼びます。
代入の左側のオペランドは変数である必要はありません (変数を参照)。行列の要素 (インデックス式を参照) または戻り値のリスト (関数の呼び出しを参照) にすることもできます。これらはすべてlvaluesと呼ばれ、代入演算子の左側に出現できます。右側のオペランドは任意の式にすることができます。これにより、代入によって指定された変数、行列要素、または戻り値のリストに格納される新しい値が生成されます。
変数には永続的な型がないことに注意してください。変数の型は、その時点でたまたま保持されている値の型です。次のプログラム フラグメントでは、変数は foo最初は数値を持ち、その後文字列値を持ちます。

>> foo = 1
foo = 1
>> foo = "bar"
foo = bar

2 番目の割り当てでfoo文字列値が与えられると、以前は数値であったという事実は忘れられます。

インデックス付き行列にスカラーを割り当てると、インデックスによって参照されるすべての要素がスカラー値に設定されます。たとえば、 a少なくとも2つの列を持つ行列の場合、

a(:, 2) = 5

の 2 番目の列のすべての要素をa5 に設定します。

代入によってベクトル、行列、または配列要素の値が、その変数の現在のサイズ外の位置または次元に設定されると、配列のサイズは新しい値に対応するために増加されます。

>> a = [1, 2, 3]
a = 1 2 3
>> a(4) = 4
a = 1 2 3 4
>> a(2, :) = [5, 6, 7, 8]
a =
  1   2   3   4
  5   6   7   8

配列のサイズを大きくして、目的の出力サイズがあいまいになるようにすると、エラーが発生します。

a(9) = 10
-| error: Invalid resizing operation or ambiguous assignment to an out-of-bounds array element

範囲外の配列要素
これは、9 番目の要素を追加すると、値 10 の目的の配列位置にあいまいさが生じ、それぞれの可能性に応じて割り当てに対応するために異なる配列サイズの拡張が必要になるためです。
割り当てが明確である限り、新しく拡張された配列を埋めるのに必要な要素よりも少ない指定要素で割り当てを行うことができます。このような場合、配列は自動的にnull値で埋められます。

>> a = [1, 2]
a =   1   2
>> a(4) = 5
a =   1   2   0   5
>> a(3, :) = [6, 7, 8, 9]
a =
  1   2   0   5
  0   0   0   0
  6   7   8   9
>> a(4, 5) = 10
a =
   1    2    0    5    0
   0    0    0    0    0
   6    7    8    9    0
   0    0    0    0   10

すべての組み込み型の場合、null値はそのオブジェクト型に適しています。

数値配列:

>> a = int32 ([1, 2])
a = 1, 2
>> a(4) = 5
a = 1 2 0 5
Logical arrays:
>> a = [true, false, true]
a = 1 0 1
>> d(5) = true
d = 1 0 1 0 1
Character arrays:
>> a = "abc"
a = abc
>> a(5) = "d"
a = abcd
>> double (a)
ans = 97 98 99 0 100
Cell arrays:
>> e = {1, "foo", [3, 4]};
>> e(5) = "bar"
e =
{
 [1,1] = 1
 [1,2] = foo
 [1,3] =
    3   4
 [1,4] = [](0x0)
 [1,5] = bar
}
Struct arrays:
>> a = struct("foo",1,"bar",2);
>> a(3) = struct("foo",3,"bar",9)
a =
 1x3 struct array containing the fields:
   foo
   bar
>> a.foo
ans = 1
ans = [](0x0)
ans = 3
>> a.bar
ans = 2
ans = [](0x0)
ans = 9

Octave は現在、任意のオブジェクト型を配列に連結することはできないことに注意してください。このような動作はオブジェクト クラス内で明示的に定義する必要があります。そうしないと、連結しようとするとエラーが発生します。オブジェクト指向プログラミングを参照してください。
空の行列を割り当てる '[]' はほとんどの場合、行列やベクトルの行や列を削除するために機能します。空行列を参照してください。たとえば、4行5列の行列Aがある場合、割り当て

A (3, :) = []

Aの3行目を削除し、割り当て

A (:, 1:2:5) = []

1 列目、3 列目、5 列目を削除します。

配列オブジェクトの一部を削除すると、必然的にオブジェクトのサイズが変更されます。削除によって次元全体にわたって一貫したサイズの縮小が可能になる場合 (たとえば、ベクトルの 1 つの要素、または行列の 1 つの行または列)、その次元に沿ったサイズは次元を維持しながら縮小されます。ただし、次元を維持できない場合は、オブジェクトは列方向の要素の順序に従ってベクトルに再形成されます。

>> a = [1, 2, 3, 4; 5, 6, 7, 8]
a =
  1   2   3   4
  5   6   7   8
>> a(:, 3) = []
a =
  1   2   4
  5   6   8
>> a(4) = []
a = 1 5 2 4 8

代入は式なので、値を持ちます。したがって、z = 1 式の値は 1 です。この結果、複数の代入をまとめて記述することができます。

x = y = z = 0

は、3 つの変数すべてに値 0 を格納します。これはz = 0、 の値 0 が に格納されy、 の値y = z = 00 が に格納されるためですx。
これは値のリストへの代入にも当てはまるので、次の式は有効です。

[a, b, c] = [u, s, v] = svd (a)

それはまさに

[u, s, v] = svd (a)
a = u
b = s
c = v

このような式では、式の各部分の値の数が一致する必要はありません。たとえば、次の式

[a, b] = [u, s, v] = svd (a)
は以下と同等である
[u, s, v] = svd (a)
a = u
b = s

ただし、式の左側の値の数は、右側の値の数を超えることはできません。たとえば、次の例ではエラーが発生します。

[a, b, c, d] = [u, s, v] = svd (a);
-| error: element number 4 undefined in return list

シンボル~は lvalues のリスト内のプレースホルダーとして使用することができ、対応する戻り値は無視され、どこにも保存されないことを示します。

[~, s, v] = svd (a);

これは、ダミー変数を使用するよりもクリーンでメモリ効率に優れています。nargout右側の式の値は影響を受けません。割り当てが式として使用される場合、戻り値は無視された値が削除されたコンマ区切りのリストになります。
非常に一般的なプログラミングパターンは、既存の変数を指定された値で増加させることです。

a = a + 2;

これは、演算子+=を使用してより明確かつ簡潔に記述できます。

a += 2;

同様の演算子は減算(-=)、乗算(*=)、除算(/=)にも存在します。m

expr1 op= expr2
は次のように評価されます
expr1 = (expr1) op (expr2)

ここで、opは、expr2が副作用のない単純な式である限り、、、、のいずれかになります。expr2に代入演算子も含まれている場合 +、この式は次のように評価されます。 -*/

temp = expr2
expr1 = (expr1) op temp

ここで、 tempはexpr2を評価して計算された結果を格納するプレースホルダの一時値です。したがって、式

a *= b+1

は次のように評価されます

a = a * (b+1)

そしてそうではない

a = a * b + 1

式が必要とされる場所であればどこでも代入を使用できます。たとえば、x != (y = 1)set yto 1 と記述してからx1 に等しいかどうかをテストすることは有効です。ただし、このスタイルではプログラムが読みにくくなる傾向があります。ワンショット プログラムを除き、このような代入のネストをなくすように書き直す必要があります。これはそれほど難しいことではありません。