Когда происходит присвоение по ссылке в MATLAB?

Это вопрос о языке MATLAB. Я изучаю учебник MathWorks "Onramp" и заметил странное поведение "назначение по ссылке" (из-за отсутствия лучшего термина), которое противоречит моим ожиданиям.

v1 = [4 6 1 3 4 9 5];

Я думаю, что в приведенном ниже примере сначала вычисляется выражение в скобках, которое генерирует логический массив [1 0 1 1 1 0 0], который затем индексирует v1 чтобы получить результат. Все идет нормально.

>> v1(v1 < 5)

ans =

     4     1     3     4

Ниже то, что меня удивляет. Если вы запустите его, вы увидите, что ans (переменная результата по умолчанию, своего рода анонимная переменная) получает значение [4 1 3 4] которая является значением левой части оператора. Я бы ожидал, что присвоение будет писать только в ans, но вместо этого оно проходит по ссылке и записывает в референтный массив v1,

>> v1(v1 < 5) = 1

v1 =

     1     6     1     1     1     9     5

Конечно, это похоже на другие языки. В print a[3] синтаксис означает, что мы получаем значение a[3], но в a[3] = 1 синтаксис означает, что мы присваиваем новое значение a[3], В этом смысле единственная "новая" часть заключается в том, что MATLAB допускает более сложные выражения индексации, чем большинство языков.

Что сбивает с толку, так это то, что MATLAB четко оценивает выражение в обоих направлениях. Он получает индексированные значения и сохраняет их в ans, но затем игнорирует это и помещает правые значения в места, на которые ссылается индекс.

Я не понимаю, как это могло бы сделать это, не оценив выражение дважды, или не применив другую магию за кадром. Я не чувствую, что у меня есть понимание порядка / правил оценки.

Спасибо за понимание того, что происходит на самом деле.

3 ответа

Один способ подумать о вашем примере

v1(v1 < 5) = 1;

рассмотреть эффективную функциональную форму, которую выполняет MATLAB. В этом случае это выражение преобразуется MATLAB в вызов функции следующим образом:

v1 = subsasgn(v1, substruct('()', {v1 < 5}), 1);

Другими словами, когда MATLAB видит индексированную форму присваивания (т. Е. Где переменная появляется в левой части =), внутренне это преобразуется в вызов функции, который принимает исходное значение и перезаписывает его. ("Оптимизация на месте" в MATLAB означает, что это, как правило, эффективно и не дублирует память). substruct инкапсулирует все детали формы индексации. Это может быть довольно сложно, если вы присваиваете часть поля struct или что-то типа того.

Я считаю, что это утверждение является ложным, и именно это вызывает путаницу:

Он получает индексированные значения и сохраняет их в ans

Что заставляет вас думать, что определенная память должна быть прочитана до того, как она будет записана? Это независимые операции.

Однако то, что вы говорите, может иметь смысл, когда мы рассматриваем сферы применения. Давайте предположим, что интерпретатор, встречая скобки (как функция), создает собственную область видимости со своей собственной ans переменная, которая затем отбрасывается после выполнения своей работы. Тогда мы не увидим эти эффекты во вложенном объеме.


Далее я хотел бы остановиться на том, что сказали Трой и Эдрик.

Насколько мне известно, разница здесь в том, как код интерпретируется во встроенные функции перед выполнением.

  • Ваш первый пример, v1(v1 < 5), интерпретируется как subsref с последующим неявным присвоением ans, Это эквивалентно написанию ans = v1(v1 < 5); в явном виде. Вот ans является результатом индексированного выражения.
  • Ваш второй пример, v1(v1 < 5) = 1, интерпретируется как subsasgn, Здесь вывод будет просто вводом после операции присваивания.

Относительно приоритета оператора смотрите эту страницу документации.

Когда вы пишете

      v1(v1 < 5)

результат выражения присваивается ans. Таким образом, приведенное выше действительно является ярлыком для

      ans = v1(v1 < 5)

И теперь мы можем увидеть разницу между этим утверждением и

      v1(v1 < 5) = 1

В первом операторе индексация происходит с правой стороны оператора присваивания. Во втором операторе индексация происходит слева. Оператор присваивания — это то, что отличает индексацию. В левой части оператора присваивания вы указываете, где вы что-то пишете. Это не оценивается. В правой части оператора присваивания вы указываете, что присваивается. Это вычисляемое выражение, результатом которого является значение (массив значений), которое присваивается тому, что находится слева.


Что приведенные выше утверждения разрешаются так же, как subsasgnили же subsrefвызовы функций не имеют отношения к пониманию основного различия между левой и правой частями оператора присваивания. Эти две функции полезны в первую очередь, если вы пишете свой собственный класс, и вам нужно перегрузить операции индексации. Они определенно не имеют отношения к новичку, которого может смутить базовый синтаксис MATLAB.

Другие вопросы по тегам