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"
(Это также демонстрирует конкатенацию строк.)
Большинство операторов (сложение, конкатенация и т. д.) не имеют эффекта, кроме вычисления значения. Если вы игнорируете значение, то можно обойтись без оператора. Оператор присваивания отличается. Он производит значение, но даже если вы игнорируете значение, присваивание всё равно оказывает влияние на переменную через изменение её значения. Мы называем это побочным эффектом.
Операнд слева от оператора присваивания не обязательно должен быть переменной (см. Переменные). Он также может быть элементом матрицы (см. Выражения индексов) или списком возвращаемых значений (см. Вызов функций). Все они называются lvalue, что означает, что они могут стоять слева от оператора присваивания. Операнд справа может быть любым выражением. Он производит новое значение, которое присваивание сохраняет в указанной переменной, элементе матрицы или списке возвращаемых значений.
Важно отметить, что переменные не имеют постоянных типов. Тип переменной — это просто тип значения, которое она хранит в данный момент. В следующем фрагменте программы переменная foo сначала имеет числовое значение, а затем строковое:
>> foo = 1 foo = 1 >> foo = "bar" foo = bar
Когда второе присваивание придаёт foo строковое значение, тот факт, что ранее оно имело числовое значение, забывается.
Присваивание скаляра индексированной матрице устанавливает все элементы, которые ссылаются на индексы, на скалярное значение. Например, если a — это матрица с как минимум двумя столбцами,
a(:, 2) = 5
устанавливает все элементы во втором столбце a равными 5.
Когда присваивание устанавливает значение вектора, матрицы или элемента массива в позиции или измерении, выходящем за пределы текущего размера переменной, размер массива увеличивается для размещения новых значений:
>> 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
Логические массивы:
>> a = [true, false, true] a = 1 0 1 >> d(5) = true d = 1 0 1 0 1
Символьные массивы:
>> a = "abc" a = abc >> a(5) = "d" a = abcd >> double (a) ans = 97 98 99 0 100
Массивы ячеек:
>> 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
} Массивы структур:
>> 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, а присваивание
A (:, 1:2:5) = []
удаляет первый, третий и пятый столбцы.
Удаление части объекта массива неизбежно изменяет размер объекта. Когда удаление позволяет обеспечить согласованное уменьшение размера по размерности, например, одного элемента вектора или одной строки или столбца матрицы, размер по этой размерности уменьшается, сохраняя размерность. Однако если размерность сохранить нельзя, объект будет преобразован в вектор, следуя порядку следования элементов по столбцам:
>> 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
хранит значение 0 во всех трёх переменных. Это происходит потому, что значение z = 0, которое равно 0, сохраняется в y, а затем значение y = z = 0, которое равно 0, сохраняется в 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
Символ ~ может использоваться в качестве заполнителя в списке lvalue, указывая, что соответствующее возвращаемое значение должно быть проигнорировано и нигде не сохранено:
[~, s, v] = svd (a);
Это более чисто и эффективнее с точки зрения памяти, чем использование фиктивной переменной. Значение nargout выражения правой стороны не изменяется. Если присваивание используется в качестве выражения, возвращаемое значение — это список, разделённый запятыми, с пропущенными игнорируемыми значениями.
Очень распространённым шаблоном программирования является увеличение существующей переменной на заданное значение, например так
a = a + 2;
Это можно записать более ясно и компактно, используя оператор +=
a += 2;
Аналогичные операторы также существуют для вычитания (-=), умножения (*=) и деления (/=). Выражение вида
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) для установки y в 1 и проверки, равно ли x 1. Однако такой стиль затрудняет чтение программ. За исключением одноразовой программы, вы должны переписать его, чтобы избавиться от такого вложенного присваивания. Это никогда не очень сложно.
© 1996–2023 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v9.2.0/Assignment-Ops.html