提问人:Xiaojun Chen 提问时间:6/30/2016 最后编辑:Sam RobertsXiaojun Chen 更新时间:7/1/2016 访问量:374
MATLAB变量传递和延迟赋值
MATLAB variable passing and lazy assignment
问:
我知道在 Matlab 中,当将新变量分配给现有变量时,会出现“惰性”评估。如:
array1 = ones(1,1e8);
array2 = array1;
除非修改了 of 的元素,否则不会将值复制到。array1
array2
array2
由此,我假设 Matlab 中的所有变量实际上都是值类型,并且都是由值传递的(尽管使用了延迟求值)。这也意味着变量是在调用堆栈上创建的。
好吧,我不是在评判它处理变量的方式,尽管我从未见过第二种编程语言这样做。我的意思是,对于可能较大的数据结构(例如数组),将其视为值类型并按值传递似乎不是一个好主意。虽然懒惰的评估节省了空间和时间,但对我来说似乎很奇怪。您可能有一个表达式,用于更改(而不是初始化或赋值)导致内存不足错误的变量。据我所知,在 C 中,数组名称实际上是指针,而在 Fortran 中,数组是通过引用传递的。大多数现代语言都撤退数组作为引用类型。
那么,谁能告诉我为什么Matlab使用这种不太常见的方法来实现数组。在 Matlab 中,堆上没有或不能创建任何内容,这是真的吗?
顺便说一句,我已经问过一些有经验的Matlab用户。他们只是说,一旦创建了变量,他们就永远不会更改它,并使用函数调用来创建新变量。这意味着所有可变数据都被视为不可变的。以这种方式编程有什么得失吗?
答:
你以一种令人困惑的方式表达你的问题,使用来自编程语言(如 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
作为值类实例的对象的行为与上述类似;作为句柄类实例的对象的行为与上述类似。
它们总是按价值传递。a
f
我猜你问题的根本原因:但我建议你看看如何创建句柄类。它们可能会为你提供你希望实现的可变行为(即能够传递它,在不显着增加内存的情况下复制它,并且它总是引用相同的底层事物)。
如果您与之交谈过的“有经验的 MATLAB 用户”只使用值变量,那么他们就会损失很多 - 使用句柄变量通常更方便。我敢打赌,他们在不知不觉中就使用了它们——几乎所有的 MATLAB Handle Graphics 都依赖于句柄变量,如上所述。f
我相信以上是对MATLAB变量语义的完整解释。还有其他一些皱纹使人们感到困惑,但它们与上述内容并不矛盾:
尽管 MATLAB 具有按值传递行为(如上所述,这与变量是否具有值或引用语义不同),但它也具有延迟或写入时复制行为。你在问题中描述了这一点,所以你显然明白了它在做什么,但这只是一个优化,与传递行为或变量语义是一个单独的问题。
正如 @Bernhard 在评论中提到的,如果您使用类似于而不是更正常的语法实现函数,则在某些情况下,MATLAB 可以对您的代码执行就地优化(即覆盖原始变量而不是制作临时副本)(特别是,在 WITHIN 中执行的操作必须能够就地完成, 例如算术或三角函数,而不是像这样的矩阵运算会改变维度)。但同样,这只是一种优化,它不会改变变量的语义。
x = myfun(x)
y = myfun(x)
x
myfun
'
PS 还有一件事 - 不要再考虑堆栈和堆了;在MATLAB中没有真正的类似物,因为你无法真正控制变量存储在哪个内存区域。
评论
x=func(x)
y=func(x)
x
func()
x=func(x)