代码之家  ›  专栏  ›  技术社区  ›  Sled bayer

Lua中pairs()的“类型签名”是什么?

lua
  •  3
  • Sled bayer  · 技术社区  · 7 年前

    看这一章 7.1 – Iterators and Closures 从“在lua中编程”看来 for foo in bar 循环需要 bar 为类型(使用Java类型表示它) Supplier<Tuple> for-in 会一直打电话 酒吧 直到它回来 nil .

    比如说:

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

    这意味着 pairs 有一种 Function<Table,Supplier<Tuple>>

    我想创建一个行为类似 除了 它跳过第一个参数以下划线开头的元组(即 _ )

    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 回复  |  直到 7 年前
        1
  •  3
  •   Jason Goemaat    7 年前

    pairs() 返回三个单独的值:

    • 用参数调用的函数 (table, key) 返回键和值的
    • 你递给它的桌子
    • 传递给函数的第一个“key”值(pairs()为nil,ipairs()为0)

    所以像这样:

    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
    

    链接到的文档有一个迭代器,它只返回一个值 配对() 返回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
    
        2
  •  5
  •   Nicol Bolas    7 年前

    您的基本问题是在Lua问题上使用Java逻辑。Java和Lua是具有不同结构的不同语言,重要的是认识到这一点。

    pairs 没有返回值;它有 倍数 返回值。这是Java完全缺乏的概念。一 Tuple 是可以存储和操作多个值的单个值。lua函数可以返回多个值。这在语法和语义上与返回表不同。 包含 多个值。

    基于迭代器 for 语句接受多个值作为其输入,而不是包含多个值的表或容器。具体来说,它存储3个值:迭代器函数、状态值(用于在调用之间保留状态)和初始值。

    所以,如果你想模仿 的行为,您需要能够存储和操作它的多个返回值。

    你的第一步是存储 实际回报:

    local f, s, var = pairs(list)
    

    您正在创建一个新的迭代器函数。所以你需要把它还给我,但是你 需要归还 s var 那个 返回。您的返回语句需要如下所示:

    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.