What does it do? What is it’s practical usage in game making?
It allows you to iterate through a dictionary.
Tables have keys associated with values, for i , v in pairs() makes it so one set of key and value is registered as one time the things within the loop will run
example:
local table = {"Car" , "Bus"}
for i , v in pairs(table) do
print(v)
end
this would print only the value of each key and not the actual key.
As stated above, it runs the loop once for each index in a table. The first variable, i
, can be used to get number of the index that the loop is on. For example:
local Example = {true, false, true, true}
for i, v in pairs(Example) do
print(i)
end
This will print 1
, 2
, 3
, and 4
(In that order).
Now, the variable v
contains the actual value for that index of the table. For example:
local Example = {true, false, true, true}
for i, v in pairs(Example) do
print(v)
end
This will print true
,false
,true
, and true
.
One way you could use this is if you want to apply an effect to a whole table of player (Or, say, the entire server). Luckily, game.Players
has a built in :GetPlayers()
function which makes this super easy, since it returns a table containing all the players in the game. This script would kill all the players in the server when run.
for i, v in pairs(game.Players:GetPlayers()) do
v.Character.Humanoid.Health = 0
end
A less evil use of this could be to delete all children or type of child of a parent. :GetChildren()
returns a table containing all of the children of an object.
This script will look through all of the children of the folder Folder
and delete any parts it finds.
for i, v in pairs(game.Workspace.Folder:GetChildren()) do
if v:IsA("BasePart") then
v:Destroy()
end
end
There are countless other applications, and I barely scratched the surface here. Let me know if you need further clarification!
i
and v
are the two values returned by the function that the pairs
iterator returns. An iterator function is just a function that is used to iterate. That is to say for ... in iter, b
where b
is some limit and ...
represents a varadic amount of variables returne per iter
call.
In the case of the question: i
being associated with the current index and value
being associated with the value tied to that index. That is to say, given a table t
, v = t[i]
.
pairs
is generally defined as being functionally equivalent to:
function pairs(t)
return next, t, nil
end
I think the point of pairs
was to create a “iterator factory” style in Lua–this is seen in gmatch
for example which is a function that creates an iterator function. (hence “factory”–it creates iterators).
In luau (ROBLOX’s optimized version of Lua 5.1) this is not really the case, but for sake of argument this will produce identical results as the pairs
function implemented in luau.
The arguments returned from the next
call are going to be i
and v
. Here is an example of a custom iterator function implementation which can be used to generate the even numbers below n
as well as their square.
local function squares(limit, cur)
cur = cur or 0
if (cur + 2 < limit) then
return cur + 2, (cur + 2)^2
end
end
local n = 14
for i, square in squares, n do
print(i, square)
end
We can extend our knowledge further to create an iterator with any amount of variables.
local function iter(limit, cur)
cur = cur or 0
if (cur < limit) then
return cur + 1, ("hello"):rep(cur), ("world"):rep(cur)
end
end
for i, h, w in iter, 4 do
print(i, h, w)
end
1
2 hello world
3 hellohello worldworld
4 hellohellohello worldworldworld
The pairs
function or for ... in func(...) do
loops in general are kind of misleading.
Before I get into that, let’s take a look at the following loop works: for var_1, ..., var_n in explist do block end
. By default, Lua only cares about a few things in that loop. According to this official Lua article, your loop becomes the equivalent of this:
do
local _f, _s, _var = explist
while true do
local var_1, ... , var_n = _f(_s, _var)
_var = var_1
if _var == nil then break end
block
end
end
All that happens is a block is repeatedly ran with the for loop’s variables until the iterator returns nil.
Contrary to popular belief, pairs(t)
is not an iterator, but instead more or less a generator function which returns an iterator function (which is not exactly equivalent to next
@DrKittyWaffles), t
, and the initial control state (nil
). Therefore, the pairs(t)
in for i, v in pairs(t) do
gets compiled into an OP_CALL instruction with 3 returns (which are the aforementioned three magic parameters) in order to match with the internally accepted semantics for generic for loops.
As far as how the iterator in for i, v in pairs(t) do
works, it goes through a table’s hash and array map with a pivot (that being the i
(state) in the loop). That means that you could also theoretically create new keys on the go as you loop through it and they will be accounted for. E.g.:
local t = {"a"}
for i, v in pairs(t) do
if i == 1 then
t[2] = "b"
end
print(i, v)
end
will print [ 1, “a” ] and [ 2, “b” ], even tho we initially started with just “a” in the array.
Most idiomatic for loops (including pairs
, ipairs
and next
ones) have since been heavily optimized by Luau and converted into a sequence of native engine opcodes tho, so my explanation above only applies for unique/custom generated iterator for loop cases.