【问题标题】:MATLAB variable passing and lazy assignmentMATLAB 变量传递和惰性赋值
【发布时间】:2023-03-08 09:37:01
【问题描述】:

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

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

array1 的值不会被复制到array2,除非array2 的元素被修改。

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

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

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

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

【问题讨论】:

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

标签: matlab lazy-evaluation pass-by-value value-type


【解决方案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 继承类来指定该类的对象是否具有值或引用/句柄语义。

作为值类实例的对象的行为类似于上面的a;作为句柄类实例的对象的行为类似于上面的f。 而且它们总是按值传递。

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

如果与您交谈过的“有经验的 MATLAB 用户”只使用值变量,那么他们会损失很多 - 使用句柄变量通常更方便。而且我敢打赌,他们在没有意识到的情况下使用它们 - 几乎所有 MATLAB Handle Graphics 都依赖于句柄变量,例如上面的 f


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

  1. 虽然 MATLAB 具有按值传递的行为(如上所述,这与变量是否具有值或引用语义不同),但它也具有 lazycopy- on-write 行为。您在问题中对此进行了描述,因此您显然知道它在做什么,但这只是一种优化,与传递行为或变量语义不同。

  2. 1234563在某些情况下(特别是在myfun 内对x 执行的操作必须能够就地完成,例如算术或三角函数,而不是矩阵运算,例如' 会改变尺寸)。但同样,这只是一种优化,它不会改变变量的语义。

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

【讨论】:

  • 感谢您的回答。只想提一下,在 C 中,指针通过它们的值传递并取消引用它们指向的内容。 “它们可以使用指针通过引用传递”的说法具有误导性。在 C++ 中,通过引用传递是通过其 reference 变量实现的。通过值或引用传递实际上与语言是否支持指针并不完全相关。以 VB.Net 和 C# 为例。
  • @XiaojunChen 我不认为我们不同意。但令人误解的是,将来自 C 的术语应用到 MATLAB 中,并且对所有其他语言都没有明确定义。
猜你喜欢
  • 1970-01-01
  • 2020-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
相关资源
最近更新 更多