MATLAB变量传递和延迟赋值

MATLAB variable passing and lazy assignment

提问人:Xiaojun Chen 提问时间:6/30/2016 最后编辑:Sam RobertsXiaojun Chen 更新时间:7/1/2016 访问量:374

问:

我知道在 Matlab 中,当将新变量分配给现有变量时,会出现“惰性”评估。如:

array1 = ones(1,1e8);
array2 = array1;

除非修改了 of 的元素,否则不会将值复制到。array1array2array2

由此,我假设 Matlab 中的所有变量实际上都是值类型,并且都是由值传递的(尽管使用了延迟求值)。这也意味着变量是在调用堆栈上创建的。

好吧,我不是在评判它处理变量的方式,尽管我从未见过第二种编程语言这样做。我的意思是,对于可能较大的数据结构(例如数组),将其视为值类型并按值传递似乎不是一个好主意。虽然懒惰的评估节省了空间和时间,但对我来说似乎很奇怪。您可能有一个表达式,用于更改(而不是初始化或赋值)导致内存不足错误的变量。据我所知,在 C 中,数组名称实际上是指针,而在 Fortran 中,数组是通过引用传递的。大多数现代语言都撤退数组作为引用类型。

那么,谁能告诉我为什么Matlab使用这种不太常见的方法来实现数组。在 Matlab 中,堆上没有或不能创建任何内容,这是真的吗?

顺便说一句,我已经问过一些有经验的Matlab用户。他们只是说,一旦创建了变量,他们就永远不会更改它,并使用函数调用来创建新变量。这意味着所有可变数据都被视为不可变的。以这种方式编程有什么得失吗?

MATLAB 惰性评估 按值传递 类型

评论

0赞 Bernhard 6/30/2016
我没有时间回答很长的答案,但 Matlab 并不总是按值传递参数。如果你执行类似 的操作,则 Matlab 将通过引用传递它。如果你做类似的事情,如果你不改变,它将通过引用传递,但如果你这样做,它将通过值传递。你不能明确地这样做,因此,在编写函数时必须小心。从不更改变量似乎是一个糟糕的解决方案。那么它怎么是一个变量呢?x=func(x)y=func(x)xfunc()
0赞 Xiaojun Chen 6/30/2016
@Bernhard Matlab 传递函数类似于通过引用,因为它的实时编译器将其视为内联函数,因此不会创建额外的调用堆栈(只要此函数不是嵌套函数)。在这里,更改变量意味着改变其值,您当然可以将变量重新分配给另一个值。x=func(x)
0赞 Xiaojun Chen 6/30/2016
@Bernhard 就像你说的,Matlab处理变量的方式会让程序员非常小心地编写代码。对我来说,创建数组(或单元格)作为值类型变量确实让我感到困惑和惊讶。因为如果不完全理解它的语义,程序员将永远不知道它们何时会造成不必要的额外计算时间和空间。

答:

0赞 Sam Roberts 7/1/2016 #1

你以一种令人困惑的方式表达你的问题,使用来自编程语言(如 C 和 FORTRAN)的术语,这些术语在应用于其他语言时具有误导性。

按值或引用传递的变量与具有值语义或引用语义的变量之间是有区别的

在 C 语言中,变量可以按值传递,也可以使用指针通过引用传递变量。

MATLAB 没有指针。无论您被告知什么,MATLAB 总是按值传递变量。由于它没有指针,因此询问它是按值还是按引用传递变量是没有意义的 - 它必须按值传递。

然而,MATLAB 变量可以具有语义或引用语义。在 MATLAB 中,具有引用语义的变量称为句柄变量。

需要强调的是,即使变量是按值传递的,它也可以具有值或引用语义。

创建常规变量时:

>> a = 1;

该变量具有值语义。这意味着,如果您从中创建另一个变量,然后更改原始变量,则新变量不会更改。a

>> b = a;
>> b
b =
     1
>> a = 2;
>> b
b =
     1

但是,如果您创建一个图形,例如:

>> f = figure;

变量具有引用或句柄语义。这意味着,如果您从中创建另一个变量,然后更改原始变量,则新变量也会更改。f

>> get(f, 'Name')
ans =
     ''
>> g = f;
>> set(f, 'Name', 'hello')
>> get(g, 'Name')
ans =
hello

使用 MATLAB OO 类定义自己的变量类型时,可以通过从内置类继承类来指定该类的对象是否具有值或引用/句柄语义。handle

作为值类实例的对象的行为与上述类似;作为句柄类实例的对象的行为与上述类似。 它们总是按价值传递。af

我猜你问题的根本原因:但我建议你看看如何创建句柄类。它们可能会为你提供你希望实现的可变行为(即能够传递它,在不显着增加内存的情况下复制它,并且它总是引用相同的底层事物)。

如果您与之交谈过的“有经验的 MATLAB 用户”只使用值变量,那么他们就会损失很多 - 使用句柄变量通常更方便。我敢打赌,他们在不知不觉中就使用了它们——几乎所有的 MATLAB Handle Graphics 都依赖于句柄变量,如上所述。f


我相信以上是对MATLAB变量语义的完整解释。还有其他一些皱纹使人们感到困惑,但它们与上述内容并不矛盾:

  1. 尽管 MATLAB 具有按值传递行为(如上所述,这与变量是否具有值或引用语义不同),但它也具有延迟写入时复制行为。你在问题中描述了这一点,所以你显然明白了它在做什么,但这只是一个优化,与传递行为或变量语义是一个单独的问题。

  2. 正如 @Bernhard 在评论中提到的,如果您使用类似于而不是更正常的语法实现函数,则在某些情况下,MATLAB 可以对您的代码执行就地优化(即覆盖原始变量而不是制作临时副本)(特别是,在 WITHIN 中执行的操作必须能够就地完成, 例如算术或三角函数,而不是像这样的矩阵运算会改变维度)。但同样,这只是一种优化,它不会改变变量的语义。x = myfun(x)y = myfun(x)xmyfun'


PS 还有一件事 - 不要再考虑堆栈和堆了;在MATLAB中没有真正的类似物,因为你无法真正控制变量存储在哪个内存区域。

评论

0赞 Xiaojun Chen 7/1/2016
谢谢你的回答。只想提一下,在 C 中,指针通过它们的值传递并取消引用它们所指向的内容。“它们可以使用指针通过引用传递”的说法具有误导性。在 C++ 中,通过引用传递是通过其引用变量实现的。按值或引用传递实际上与语言是否支持指针不太相关。以 VB.Net 和 C# 为例。
0赞 Sam Roberts 7/1/2016
@XiaojunChen我不认为我们不同意。但具有误导性的是,在MATLAB中应用了来自C语言的术语,并且没有为所有其他语言明确定义。