Что такое «сигнатура типа» пар () в Lua? - PullRequest
0 голосов
/ 07 июня 2018

Глядя на главу 7.1 - Итераторы и замыкания из "Программирование на Lua", кажется, что для цикла for foo in bar требуется тип bar (для его выражения используются типы Java) Supplier<Tuple> и for-in будет продолжать вызывать bar, пока не вернется nil.

Так что для чего-то вроде:

for k,v in pairs( tables ) do
    print( 'key: '..k..', value: '..v )
end

, что означает, что pairs имеет типFunction<Table,Supplier<Tuple>>.

Я хочу создать функцию, которая ведет себя как pairs , за исключением , она пропускает кортежи, где первый аргумент начинается с подчеркивания (то есть _).

local function mypairs( list )
    local --[[ Supplier<Tuple> ]] pairIterator = pairs( list )
    return --[[ Supplier<Tuple> ]] function ()
        while true do
            local key, value = pairIterator()
            if key == nil then
                return nil
            elseif key:sub(1,1) ~= '_' then
                return key, value
            end
        end
    end
end

однако он не работает с

--[[should be: Supplier<Table>]] pairIterator = pairs({ c=3; b=2; a=1 })

, когда я его называю

pairIterator()

, возвращается

stdin:1: bad argument #1 to 'pairIterator' (table expected, got no value)
stack traceback:
    [C]: in function 'pairIterator'
    stdin:1: in main chunk
    [C]: in ?

, но

pairIterator({ c=3; b=2; a=1 })

возвращает

Lua>pairIterator({ c=3; b=2; a=1 })
c       3

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

pairs() возвращает три отдельных значения:

  • функция для вызова с параметрами (table, key), которая возвращает ключ и значение
  • таблицы, которую вы передали ей
  • первое значение ключа для передачи в функцию (ноль для пар (), 0 для ipairs ())

Примерно так:

for k,v in pairs({a=1, b=13, c=169}) do print(k, v) end

Это можно сделать следующим образом:

local f,t,k = pairs({a=1, b=13, c=169})
local v
print('first k: '..tostring(k))
k,v = f(t, k)
while k ~= nil do
  print('k: '..tostring(k)..', v: '..tostring(v))
  k,v = f(t, k)
end

Результаты:

first k: nil
k: c, v: 169
k: b, v: 13
k: a, v: 1

И вам не нужно принимать аргумент, здесь есть инструкции if для каждого значения:

function mypairs()
  -- the function returned should take the table and an index, and
  -- return the next value you expect AND the next index to pass to
  -- get the value after.  return nil and nil to end
  local myfunc = function(t, val)
    if val == 0 then return 1, 'first' end
    if val == 1 then return 2, 'second' end
    if val == 2 then return 3, 'third' end
    return nil, nil
  end

  -- returns a function, the table, and the first value to pass
  -- to the function
  return myfunc, nil, 0
end

for i,v in mypairs() do
  print('i: '..tostring(i)..', v: '..tostring(v))
end

-- output:
-- i: 1, v: first
-- i: 2, v: second
-- i: 3, v: third

Для вашего mypairs(list) вы можете просто продолжать вызывать функцию, возвращаемую из пар, до тех пор, пока у ключа есть подчеркивание, чтобы получить следующее значение:

local function mypairs( list )
  local f,t,k = pairs(list)
  return function(t,k)
    local a,b = f(t, k)
    while type(a) == 'string' and a:sub(1,1) == '_' do  a,b = f(t,a) end
    return a,b
  end, t, k
end

local list = {a=5, _b=11, c = 13, _d=69}
for k,v in mypairs(list) do print(k, v) end

-- output:
-- c    13
-- a    5

Документы, на которые вы ссылаетесь, чтобы иметьитератор, который возвращает только одно значение, а pairs() возвращает 2, но вы можете вернуть больше, если хотите.Конструкция for ... in ... будет выполнять тело, только если первое значение не равно нулю.Вот версия, которая также возвращает пропущенные ключи, тело не будет выполнено, если вы не получите действительное значение, хотя, возможно, вы не увидите все клавиши _:

local function mypairs( list )
  local f,t,k = pairs(list)
  return function(t,k)
    local skipped = {}
    local a,b = f(t, k)
    while type(a) == 'string' and a:sub(1,1) == '_' do
      table.insert(skipped, a)
      a,b = f(t,a)
    end
    return a,b,skipped
  end, t, k
end

local list = {a=5, _b=11, c = 13, _d=69}
for k,v,skipped in mypairs(list) do
  for i,s in ipairs(skipped) do
    print('Skipped: '..s)
  end
  print(k, v)
end
0 голосов
/ 07 июня 2018

Ваша основная проблема в том, что вы используете Java-логику для задач Lua.Java и Lua - это разные языки с разными конструкциями, и важно понимать, что.

pairs не имеет возвращаемого значения;он имеет несколько возвращаемых значений.Это понятие, которого в Java совершенно не хватает.Tuple - это одно значение, которое может хранить и манипулировать несколькими значениями.Функция Lua может возвращать несколько значений.Это синтаксически и семантически отличается от возврата таблицы , содержащей нескольких значений.

Оператор for на основе итератора принимает в качестве входных данных несколько значений, а не таблицу или контейнер с несколькими значениями.В частности, он хранит 3 значения: функцию итератора, значение состояния (которое вы используете для сохранения состояния между вызовами) и начальное значение.

Итак, если вы хотите имитировать поведение pairs,вам нужно иметь возможность хранить и манипулировать его множественными возвращаемыми значениями.

Ваш первый шаг - сохранить то, что на самом деле возвращает pairs:

local f, s, var = pairs(list)

Вы создаете новую функцию итератора.Таким образом, вы должны вернуть это, но вам также необходимо вернуть s и var, которые pairs возвращает.Ваш оператор возврата должен выглядеть следующим образом:

return function (s, var)
    --[[Contents discussed below]]
end, s, var --Returning what `pairs` would return.

Теперь внутри вашей функции вам нужно вызвать f с s и var.Эта функция вернет пару ключ / значение.И вам нужно правильно их обработать:

return function (s, var)
    repeat
        local key, value = f(s, var)
        if(type(key) ~= "string") then
            --Non-string types can't have an `_` in them.
            --And no need to special-case `nil`.
            return key, value
        elseif(key:sub(1, 1) ~= '_') then
            return key, value
        end
    until true
end, s, var --Returning what `pairs` would return.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...