Подтвердить что ты не робот

Область функций/переменных (передается по значению или ссылке?)

Меня полностью смущает Lua передача аргументов переменных и функций (значение или ссылка).

Смотрите код ниже:

local a = 9        -- since it define local, should not have func scope
local t = {4,6}    -- since it define local, should not have func scope

function moda(a)
  a = 10           -- creates a global var?
end
function modt(t)
  t[1] = 7         -- create a global var?
  t[2] = 8
end

moda(a)
modt(t)
print(a)  -- print 9 (function does not modify the parent variable)
print(t[1]..t[2])  -- print 78 (some how modt is modifying the parent t var) 

Таким образом, это поведение полностью меня смущает.

  • Означает ли это, что переменные таблицы передаются функции ссылка, а не значение?

  • Как создается глобальная переменная противоречащие уже локальная переменная?

    • Почему modt способен еще не измените таблицу moda не в состоянии изменить переменную?
4b9b3361

Ответ 1

Вы правильно поняли, переменные таблицы передаются по ссылке. Цитирование Справочное руководство Lua 5.1:

В Lua существует восемь основных типов: nil, boolean, number, string, function, userdata, thread и table.....

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

Итак, nil, booleans, числа и строки передаются по значению. Это точно объясняет поведение, которое вы наблюдаете.

Ответ 2

Lua function, table, userdata и thread (сопрограммы) передаются по ссылке. Другие типы передаются по значению. Или, как это делают некоторые люди; все типы передаются по значению, но function, table, userdata и thread являются ссылочными типами.

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

Вот что происходит:

local a = 9
local t = {4,6}

function moda(a)
  a = 10 -- sets 'a', which is a local introduced in the parameter list
end

function modt(t)
  t[1] = 7 -- modifies the table referred to by the local 't' introduced in the parameter list
  t[2] = 8
end

Возможно, это поставит под вопрос то, почему все так:

local a = 9
local t = {4,6}

function moda()
  a = 10 -- modifies the upvalue 'a'
end

function modt()
  t[1] = 7 -- modifies the table referred to by the upvalue 't'
  t[2] = 8
end

-- 'moda' and 'modt' are closures already containing 'a' and 't',
-- so we don't have to pass any parameters to modify those variables
moda()
modt()
print(a)  -- now print 10
print(t[1]..t[2])  -- still print 78

Ответ 3

jA_cOp верен, когда он говорит: "все типы передаются по значению, но функция, таблица, данные пользователя и поток являются ссылочными типами".

Разница между этим и "таблицами передается по ссылке" важна.

В этом случае это не имеет значения,

function modt_1(x)
  x.foo = "bar"
end

Результат: как "передать таблицу по ссылке", так и "передать таблицу по значению, но таблица является ссылочным типом" будет делать то же самое: x теперь имеет свое поле foo, установленное в "bar".

Но для этой функции он создает мир различий

function modt_2(x)
  x = {}
end

В этом случае pass by reference приведет к изменению аргумента в пустую таблицу. Однако в "pass by value, но его ссылочном типе" новая таблица будет локально привязана к x, и аргумент останется неизменным. Если вы попробуете это в lua, вы обнаружите, что это второй (значения являются ссылками), которые происходят.

Ответ 4

Я не буду повторять то, что уже было сказано в Bas Bossink, и ответы jA_cOp о ссылочных типах, но:

- поскольку он определяет локальный, не должен иметь функциональную область

Это неверно. Переменные в Lua лексически ограничены, то есть они определены в блоке кода и всех его вложенных блоках.
Что означает local - это создать новую переменную, которая ограничена блоком, где находится оператор, причем блок является либо телом функции, либо "уровнем отступов", либо файлом.

Это означает, что всякий раз, когда вы делаете ссылку на переменную, Lua будет "сканировать вверх" до тех пор, пока не найдет блок кода, в котором эта переменная объявлена ​​локальной, по умолчанию для глобальной области, если такой декларации нет.

В этом случае a и t объявляются локальными, но объявление находится в глобальной области видимости, поэтому a и t являются глобальными; или не более, они локальны для текущего файла.

Затем они не обновляются в local внутри функций, но они объявляются как параметры, которые имеют тот же эффект. Если бы они не были функциональными параметрами, любая ссылка внутри тел функции все равно будет ссылаться на переменные снаружи.

Там Учебник по областям на lua-users.org с некоторыми примерами, которые могут помочь вам больше, чем моя попытка объяснения. Программирование в разделе Lua по теме также хорошо читается.

Ответ 5

Означает ли это, что переменные таблицы передаются функции по ссылке, а не значения?

Да.

Как создается глобальная переменная, конфликтующая с уже определенной локальной переменной?

Это не так. Возможно, это так, потому что у вас есть глобальная переменная с именем t и передать ее функции с аргументом t, но два t отличаются. Если вы переименуете аргумент на что-то другое, e, g, q, вывод будет точно таким же. modt(t) может изменять глобальную переменную t только потому, что вы передаете ее по ссылке. Если вы вызываете modt({}), например, глобальный t не будет затронут.

Почему modt способен изменять таблицу, но moda не может изменить переменную?

Потому что аргументы являются локальными. Именование вашего аргумента a аналогично объявлению локальной переменной с local a, за исключением, очевидно, что аргумент получает переданное значение, а регулярная локальная переменная - нет. Если ваш аргумент был вызван z (или вообще отсутствовал), то moda действительно изменит глобальный a.