赋值是将新值存入变量的表达式。例如,以下表达式将值 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"
(这也演示了字符串的连接。)
大多数运算符(加法、连接等)除了计算值外没有其他效果。如果你不打算使用这个值,那么最好不要使用该运算符。赋值运算符则不同:它确实返回一个值,但即使你忽略了该值,赋值操作仍然会通过改变变量的方式产生影响。我们称这种效果为副作用。
赋值的左侧操作数不一定是一个变量(参见 变量)。它可以是矩阵的元素(参见 索引表达式),或是返回值列表(参见 调用函数)。这些统称为左值,意味着它们可以出现在赋值运算符的左侧。右侧操作数可以是任何表达式,它产生新值,赋值操作将其存入指定的变量、矩阵元素或返回值列表中。
需要强调的是,变量 没有 固定的类型。变量的类型就是它当前所持有值的类型。在下面的代码片段中,变量 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 应放置的数组位置存在歧义,不同的可能性需要不同的数组扩展方式来容纳该赋值。
只要赋值是明确的,就可以使用比填充新扩展数组所需更少的指定元素进行赋值。在这种情况下,数组将自动用 空 值填充:
>> 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
对于所有内置类型,空 值采用该对象类型所对应的空值。
数值数组:
>> 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
符号 ~ 可以用作左值列表中的占位符,指示对应的返回值应被忽略而不存储:
[~, 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。但这种风格往往会使程序难以阅读。除非是一次性程序,否则应重写代码以消除这种嵌套赋值,这通常不难做到。
版权所有 © 2024-2026 Octave中文网
ICP备案/许可证号:黑ICP备2024030411号-2