我知道在Matlab中,有一个“懒惰的”#39;将新变量分配给现有变量时的评估。如:
array1 = ones(1,1e8);
array2 = array1;
除非array1
的元素被修改,否则array2
的值不会被复制到array2
。
由此我认为Matlab中的所有变量实际上都是值类型,并且都是通过值传递的(尽管使用了惰性求值)。这也意味着变量是在调用堆栈上创建的。
好吧,我不是在判断它对待变量的方式,尽管我从未见过第二种编程语言这样做。我的意思是,对于可能的大型数据结构(如数组),将其视为值类型并通过值传递它似乎不是一个好主意。虽然懒惰的评估节省了空间和时间,但对我来说这似乎很奇怪。您可能有一个表达式用于变量(而不是初始化或赋值)变量,从而导致内存不足错误。据我所知,在C数组中,名称实际上是指针,而在Fortran中,数组是通过引用传递的。大多数现代语言都将数组作为引用类型撤销。
那么,任何人都可以告诉我为什么Matlab使用这种不那么常见的方式来实现数组。是不是在Matlab中,堆上什么都没有或者什么都可以创建?
顺便说一下,我已经向一些经验丰富的Matlab用户询问过它。他们只是说他们在创建变量后永远不会更改变量,并使用函数调用来创建新变量。这意味着所有可变数据都是不可变的。以这种方式编程是否有任何收益或损失?
答案 0 :(得分:0)
您使用C和FORTRAN等编程语言中的术语以混乱的方式表达您的问题,这些术语在应用于其他语言时会产生误导。
通过引用或通过引用传递的变量与具有值语义或引用语义<的变量之间存在区别/ em>的
在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具有按值传递的行为(如上所述与变量具有值或引用语义不同),但它也具有 lazy 或 copy-写入行为。你在问题中描述了这一点,所以你显然得到它正在做的事情,但它只是一个优化,它与传递行为或变量语义是一个单独的问题。
正如@Bernhard在评论中所提到的,如果使用类似于x = myfun(x)
的语法而不是更正常的y = myfun(x)
来实现函数,MATLAB可以对代码执行就地优化(即覆盖原始变量而不是制作临时副本)在某些情况下(特别是x
myfun
内执行的操作必须能够就地完成,例如算术或三角函数,而不是像'
那样会改变尺寸的矩阵运算。但同样,这只是一种优化,它不会改变变量的语义。
PS还有一件事 - 不要再考虑堆栈和堆了;在MATLAB中并没有真正的模拟,因为你实际上无法控制变量存储在哪个内存区域。