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=1foo=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

符号~可以用作lvalues列表中的占位符,指示应忽略相应的返回值而不存储其中:

[~, 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 Octave中文网

ICP备案/许可证号:黑ICP备2024030411号