For (lua)

3.3 – Операторы

3.3.1 – Блоки

block ::= {stat}

пустые операторы

stat ::= ‘;
a = b + c
(print or io.write)('done')
a = b + c(print or io.write)('done')
a = b + c; (print or io.write)('done')

парсер

;(print or io.write)('done')
stat ::= do block end

return

3.3.2 – Порции

порция

chunk ::= block

_ENV_ENVзагружаетпрограмму luac
Примечание: Интерпретатор — программа (разновидность транслятора), выполняющая интерпретацию, … читать далее

3.3.3 – Присваивание

stat ::= varlist ‘=’ explist
varlist ::= var {‘,’ var}
explist ::= exp {‘,’ exp}

согласовываетсяnil

i = 3
i, a = i+1, 20

aaia

x, y = y, x

xy

x, y, z = y, z, x

xyzt = valsettable_event(t,i,val)settable_eventx = val_ENV.x = val

3.3.4 – Управляющие структуры

ifwhilerepeat

stat ::= while exp do block end
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] end

forfalsenilnilfalserepeatuntiluntilgoto

stat ::= goto Name
stat ::= label
label ::= ‘::’ Name ‘::

gotoнедействующими операторамиbreakwhilerepeatfor

stat ::= break

breakreturnreturn

stat ::= return  [‘;’]

returnreturndo return endreturn

3.3.5 – Оператор for

forforарифметическую прогрессию

stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

blocknameexpexpexpfor

for v = e1, e2, e3 do block end
do
  local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
  if not (var and limit and step) then error() end
  var = var - step
  while true do
    var = var + step
    if (step >= 0 and var > limit) or (step < 0 and var < limit) then
      break
    end
    local v = var
    block
  end
end
  • Все три управляющих выражения вычисляются только один раз, перед началом цикла. Все они должны быть приведены в числах.
  • var (переменная), limit (предел), и step (шаг) — невидимые (неявные) переменные. Имена, показанные здесь, приведены только для пояснения.
  • Если третье выражение (step) отсутствует, то используется шаг равный 1.
  • Для выхода из цикла for можно использовать break и goto.
  • Переменная цикла v является локальной для тела цикла. Если потребуется её значение после цикла, назначьте его в другую переменную перед выходом из цикла.

forитераторамиnilfor

stat ::= for namelist in explist do block end
namelist ::= Name {‘,’ Name}

for

for var_1, ..., var_n in explist do block end
do
  local f, s, var = explist
  while true do
    local var_1, ..., var_n = f(s, var)
    if var_1 == nil then break end
    var = var_1
    block
  end
end
  • explist вычисляется только один раз. Его результатами являются функция iterator, state и начальное значение для первой переменной итератора.
  • f, s, и var являются неявными переменными. Имена, используемые здесь, только для пояснения.
  • Для выхода из цикла for можно использовать break.
  • Переменные цикла var_i являются локальными для цикла, их значения нельзя использовать после завершения цикла for.
    Если все же эти значения потребовались, то присвойте их другим переменным перед тем как прервать цикл или выйти из него.

6.3 – Модули

package

require (modname)

modnamerequirepackage.loadedloaderrequirerequirerequirepackage.preloadrequireвсе-в-одномrequiremodnamenilrequirepackage.loadednilpackage.loadedrequiretruerequirepackage.loadedrequire

package.config

  • Первая строка — значение разделителя каталогов. По умолчанию им является ‘\‘ для Windows и » для всех остальных систем.
  • Вторая строка — символ, разделяющий шаблоны в пути. По умолчанию это ‘;‘.
  • Третья строка — значение, которое маркирует точки замен в шаблоне. По умолчанию это ‘?‘.
  • Четвертой строкой является строковое значение, которое в пути Windows заменяется каталогом выполнения. По умолчанию это ‘!‘.
  • Пятой строкой является знак игнорирования всего текста после него, при построении имени функции luaopen_. По умолчанию это ‘-‘.

package.searchers

функцией поисковикомзагрузчикnil

     "./?.so;./?.dll;/usr/local/?/init.so"

foo./foo.so./foo.dll/usr/local/foo/init.soluaopen_a.b.c-v2.1luaopen_a_b_cвсе-в-одномa.b.caluaopen_a_b_c

package.searchpath (name, path ])

namepathшаблоновnameseprep

"./?.lua;./?.lc;/usr/local/?/init.lua"

foo.a./foo/a.lua./foo/a.lc/usr/local/foo/a/init.luanil

2.5 – Tables

The table type implements associative arrays.
An associative array is an array
that can be indexed not only with numbers,
but also with strings or any other value of the language,
except nil.
Moreover, tables have no fixed size;
you can add as many elements as you want to a table dynamically.
Tables are the main (in fact, the only) data structuring mechanism in Lua,
and a powerful one.
We use tables to represent ordinary arrays,
symbol tables, sets, records, queues, and other data structures,
in a simple, uniform, and efficient way.
Lua uses tables to represent packages as well.
When we write ,
we mean «the entry from the package».
For Lua, that means
«index the table using the string as the key».

Tables in Lua are neither values nor variables;
they are objects.
If you are familiar with arrays in Java or Scheme,
then you have a fair idea of what we mean.
However, if your idea of an array comes from C or Pascal,
you have to open your mind a bit.
You may think of a table as a dynamically allocated object;
your program only manipulates references (or pointers) to them.
There are no hidden copies or creation of new tables
behind the scenes.
Moreover, you do not have to declare a table in Lua;
in fact, there is no way to declare one.
You create tables by means of a constructor expression,
which in its simplest form is written as :

    a = {}     -- create a table and store its reference in `a'
    k = "x"
    a = 10        -- new entry, with key="x" and value=10
    a = "great"  -- new entry, with key=20 and value="great"
    print(a)    --> 10
    k = 20
    print(a)      --> "great"
    a = a + 1     -- increments entry "x"
    print(a)    --> 11
    a = {}
    a = 10
    b = a      -- `b' refers to the same table as `a'
    print(b)  --> 10
    b = 20
    print(a)  --> 20
    a = nil    -- now only `b' still refers to the table
    b = nil    -- now there are no references left to the table

Each table may store values with different types of indices
and it grows as it needs to accommodate new entries:

    a = {}     -- empty table
    -- create 1000 new entries
    for i=1,1000 do a = i*2 end
    print(a)    --> 18
    a = 10
    print(a)  --> 10
    print(a)  --> nil

nilnil

To represent records, you use the field name as an index.
Lua supports this representation by
providing as syntactic sugar for .
So, we could write the last lines of the previous example
in a cleanlier manner as

    a.x = 10                    -- same as a = 10
    print(a.x)                  -- same as print(a)
    print(a.y)                  -- same as print(a)

A common mistake for beginners is to confuse with .
The first form represents , that is, a table indexed by
the string .
The second form is a table indexed by the value of the variable .
See the difference:

    a = {}
    x = "y"
    a = 10                 -- put 10 in field "y"
    print(a)   --> 10      -- value of field "y"
    print(a.x)    --> nil     -- value of field "x" (undefined)
    print(a.y)    --> 10      -- value of field "y"

To represent a conventional array,
you simply use a table with integer keys.
There is no way to declare its size;
you just initialize the elements you need:

    -- read 10 lines storing them in a table
    a = {}
    for i=1,10 do
      a = io.read()
    end

nil

    -- print the lines
    for i,line in ipairs(a) do
      print(line)
    end

Since you can index a table with any value,
you can start the indices of an array with
any number that pleases you.
However, it is customary in Lua to start arrays with one
(and not with zero, as in C)
and the standard libraries stick to this convention.

Because we can index a table with any type,
when indexing a table
we have the same subtleties that arise in equality.
Although we can index a table both with the
number and with the string ,
these two values are different (according to equality)
and therefore denote different positions in a table.
By the same token, the strings , ,
and all denote different positions.
When in doubt about the actual types of your indices,
use an explicit conversion to be sure:

    i = 10; j = "10"; k = "+10"
    a = {}
    a = "one value"
    a = "another value"
    a = "yet another value"
    print(a)            --> another value
    print(a)            --> yet another value
    print(a)  --> one value
    print(a)  --> one value

Copyright 2003–2004 Roberto Ierusalimschy. All rights reserved.

Специальные функции

Некоторые имена функций таблиц (методов) зарезервированы, и они несут особый смысл:

* __add(a, b), __sub(a, b), __div(a, b), __mul(a, b), __mod(a, b), __pow(a, b) — вызываются, когда выполняются арифметические операции над таблицей
* __unm(a) — унарная операция «минус» (когда пишут что-то типа «x = -x»)
* __lt(a, b), __le(a, b), __eq(a, b) — вычисляют результат сравнения (<, <=, ==)
* __len(a) — вызывается, когда делается «#a»
* __concat(a, b) — вызывается при «a..b»
* __call(a, …) — вызывается при «a()». Переменные аргументы — это аргументы при вызове
* __index(a, i) — обращение к a, при условии, что такого элемента не существует
* __newindex(a, i, v) — создание «a = v»
* __gc(a) — когда объект удаляется при сборке мусора

Подменяя эти методы, можно перегружать операторы и использовать синтаксис языка для своих целей. Главное не переусердствовать.

3 ответа

Лучший ответ

С моей стороны это всего лишь догадки, но:

1. Это сложно реализовать в однопроходном компиляторе.

Компилятор байт-кода Lua реализован как однопроходный рекурсивный анализатор спуска, который немедленно генерирует код. Он не анализирует отдельную структуру AST, а затем во втором проходе преобразует ее в байт-код.

Это накладывает некоторые ограничения на грамматику и семантику. В частности, в этой модели действительно сложно поддерживать все, что требует произвольных ссылок вперед или вперед. Это означает, что присвоения уже трудно анализировать. Учитывая что-то вроде:

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

Поддержка самостоятельного назначения сделает это еще труднее. Что-то вроде:

Необходимо перевести на:

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

2. Это может плохо сказаться на грамматике

Lua фактически не имеет в грамматике каких-либо операторов или разделителей строк. Пробелы игнорируются, и точки с запятой не используются. Ты можешь сделать:

Или же:

И Lua одинаково доволен обоими. Сохранять такую ​​грамматику недвусмысленной непросто. Я не уверен, но операторы самостоятельного присваивания могут усложнить задачу.

3. Это не очень хорошо с несколькими заданиями

Lua поддерживает множественное назначение, например:

Мне даже не ясно, что это значило бы, если бы вы попытались сделать:

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

При всем этом не совсем ясно, достаточно ли полезны операторы самоназначения, чтобы иметь дело с указанными выше проблемами.

66

munificent
3 Дек 2013 в 21:47

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

В

Или в

Первая версия запускает метаметод для дважды, а вторая — только один раз. Отсутствие самоопределения в языке и принуждение к откровенности помогает избежать этой двусмысленности.

12

hugomg
3 Янв 2014 в 16:22

Я думаю, вы могли бы просто переписать этот вопрос как

Обычно это компромисс, который разработчики языка делают, исходя из своего видения того, для чего предназначен язык, и своих целей.

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

Если вы реализуете каждую крошечную функцию, вы можете получить язык «кухонной раковины»: ADA , кто-нибудь?

И, как вы говорите, это просто синтаксический сахар.

15

Roddy
20 Ноя 2013 в 09:32

Примеры циклов обхода массивов

--lua
local arr = {40, 50, 20, 10}  -- массив arr, элементы:  = 40,  = 50,  = 20,  = 10
log ("clear")           -- очистить лог  
log ("mode compact")    -- компактный режим
for i = 1, #arr do      -- #arr - размер массива arr
    log (i, arr)
end 
log()
-- или так
for i, value in ipairs(arr) do
    log (i, value)
end 
-- Когда в массиве отсутствуют пустые элементы (nil) между #arr и ipairs разницы нет.
--lua 
local arr = { = 40,  = 50,  = 10}  -- массив arr, элементы:  = 40,  = 50,  = nil,  = 10, такая индексация не рекомендуется
log ("clear")           -- очистить лог  
log ("mode compact")    -- компактный режим
for i = 1, #arr do     
    log (i, arr)
end 
log()
for i, value in ipairs(arr) do
    log (i, value)
end 
-- А в этом примере разница заметна. 3й элемент пуст поэтому ipairs обошёл только элементы 1 и 2.
--lua 
local arr = { = 40,  = 50,  = 10}  -- массив arr, элементы:  = 40,  = 50,  = nil,  = 10
log ("clear")           -- очистить лог  
log ("mode compact")    -- компактный режим
for i, value in pairs(arr) do
    log (i, value)
end 
-- pairs обходит все элементы массива, но не обязательно по порядку. 

Условия

Любое условие имеет вид:
if … then
end
--lua
local a = 13
if a == 13 then    -- если переменная 'a' равна 13   
    log ("Условие выполнено, т. к. переменная a равна 13")
end                -- конец условия
--lua
local a = 4
local b = 7 + a
if b == 11 then    -- если переменная 'b' равна 11   
    log ("Переменная b равна 11")
end
--lua
local x, y = 10, 30
if x + y == 40 then    -- если сумма 'x' и 'y' равна 40
    log ("+++")
end   
Условия с else.

else выполняет другое действие, если условие c if не выполнилось.

--lua
local x = 100
if x > 101 then    -- если 'x' больше 101
    log ("x больше 101")
else               -- иначе
    log ("x меньше 101")
end
Условия с elseif.
--lua
local a = 15
local b = 0
if a > 20 then     -- если а больше 20
    b = 3          -- присвоить 3 переменной b
elseif a < 20 then -- если же а меньше 20
    b = 1          -- присвоить 1 переменной b
else               -- иначе
    b = -1         -- присвоить -1 переменной b
end
log (b)
Несколько условий в одном if.
--lua
local x = 5
local y = 7
if x == 5 and y == 7 then    -- если x равен 5 и y равен 7
    log ("+++")
end
--lua
local x = 5
local y = 7
if x == 5 or y == 10 then    -- если x равен 5 или y равен 10
    log ("+++")
end

Обработка ошибок

Часто, если возникают ошибки, надо прекратить выполнение определенной функции. Можно, конечно, сделать множество проверок и вызывать «return», если что-то пошло не так. Но это увеличит объем кода. В Lua используется что-то наподобие исключений (exceptions).

Ошибки порождаются с помощью функции error(x). В качестве аргумента можно передать все, что угодно (то, что имеет отношение к ошибке — строковое описание, числовой код, объект, с которым произошла ошибка и т.д.)

Обычно после этой функции вся программа аварийно завершается. А это надо далеко не всегда. Если вы вызываете функцию, которая может создать ошибку (или ее дочерние функции могут создать ошибку), то вызывайте ее безопасно, с помощью pcall():

function f(x, y)
...
  if ... then
    error("failed to do somthing")
  end
...
end

status, err = pcall(f, x, y) -- f:функция, x-y: ее аргументы
if not status then 
  -- обработать ошибку err. В нашем случае в err находится текст ошибки
end

Синтаксис

Привязка к окну: нет.
Работа со свернутым окном: да.
1-й тип (числовой цикл):

for i = iMin, iMax  do
  
  
  
end

Где:
i — числовая переменная-счётчик
iMin — начальное значение отсчета.
iMax — конечное значение отсчета (включительно).
шаг — шаг цикла (значение, которое при каждом цикле прибавляется к i). Может быть положительным или отрицательным. Необязателен. Если не указан, то равен 1.
iMin, iMax, шаг — вычисляются только один раз, перед выполнением цикла.
break — команда прерывания цикла. Передаёт управление на строку, находящуюся сразу за end.
Допустимо использование дробных чисел. Разделитель точка.
2-й тип (обход элементов массива/таблицы):
Условно можно разделить на 2 вида: pairs и ipairs.
ipairs — цикл перебирает все элементы массива/таблицы с целочисленными ключами в порядке возрастания начиная с единицы. Если значение элемента массива/таблицы nil, то выполняется выход из цикла.
pairs — используется для обхода вообще всех элементов массива/таблицы. Порядок обхода элементов непредсказуем, даже при использовании целочисленных ключей.

for i, value in ipairs(Array) do
    
    
    
end

Где:
i — переменная, в которую записывается индекс элемента массива/таблицы.
value — переменная, в которую записывается значение элемента массива/таблицы.
Array — массив или таблица.

for i, value in pairs(Array) do
    
    
    
end

Где:
i — переменная, в которую записывается ключ элемента массива/таблицы.
value — переменная, в которую записывается значение элемента массива/таблицы.
Array — массив или таблица.

Объекты = функции + таблицы

Раз мы можем сохранять функции в переменных, то и в полях таблиц тоже сможем. А это уже получаются как-бы-методы. Для тех, кто не знаком с ООП скажу, что основная его польза (по крайней мере в Lua) в том, что функции и данные, с которыми они работают находятся рядом — в пределах одного объекта. Для тех, кто знаком с ООП скажу, что классов здесь нет, а наследование прототипное.

Перейдем к примерам. Есть у нас объект, скажем, лампочка. Она умеет гореть и не гореть. Ну а действия с ней можно сделать два — включить и выключить:

lamp = {
  on = false
}

function turn_on(l)
  l.on = true
end

function turn_off(l)
  l.on = false
end

-- это просто функции для работы со структурой
turn_on(lamp)
turn_off(lamp)

А если лампочку сделать объектом, и функции turn_off и turn_on сделать полями объекта, то получится:

lamp = {
  on = false
  turn_on = function(l) l.on = true end
  turn_off = function(l) l.on = false end 
}
lamp.turn_on(lamp)
lamp.turn_off(lamp)

Мы вынуждены передавать сам объект лампочки в качестве первого аргумента, потому что иначе наша функция не узнает с какой именно лампочкой надо работать, чтобы сменить состояние on/off. Но чтобы не быть многословными, в Lua есть сокращенная запись, которую обычно и используют — lamp:turn_on(). Итого, мы уже знаем несколько таких упрощений синтаксиса:

lamp:turn_on() -- самая общепринятая запись
lamp.turn_on(lamp) -- то с точки зрения синтаксиса это тоже правильно
lamp(lamp) -- и это

Продолжая говорить о сокращениях, функции можно описывать не только явно, как поля структуры, но и в более удобной форме:

lamp = {
  on = false
}

-- через точку, тогда аргумент надо указывать
function lamp.turn_on(l) l.on = true end

-- через двоеточкие, тогда аргумент неявно задается сам, как переменная "self"
-- "self" - и есть та лампочка, для которой вызвали метод
function lamp:turn_off() self.on = false end

Интересно?

Переменные

Объявление переменной и присваивание значения.
--lua
local a = 3        -- объявить переменную "a" и присвоить ей значение 3
local b = 5        -- объявить переменную "b" и присвоить ей значение 5 
log (a, b)   -- вывести в лог значение переменной a и b
Переменные чувствительны к регистру.
--lua
local a = 1
local A = 2
log (a, A)  -- a и A это разные переменные
Можно присваивать значения нескольким переменным
--lua
local a, b, c = 3, 1, 6
log (a, b, c)
А так же менять их значения местами.
--lua
local a, b = 10, 35
log (a, b)
a, b = b, a   -- присвоить переменной 'a' значение переменной 'b' и переменной 'b' значение 'a'
log (a, b)
--lua
local a, b, c, d = 11, 22, 33, 44
a, b, c, d = d, c, b, a
log (a, b, c, d)
Переменные могут содержать разные данные.
--lua
local x = 2    -- содержит число
local s = "это строка"   -- любые символы, кроме чисел, заключаются в кавычки "текст" или 'текст'
log (x, s)

6.1 – Основные функции

collectgarbage (])

opt

  • «collect«: выполняет полный цикл сборки мусора. Это опция по умолчанию.
  • «stop«: останавливает автоматическое выполнение сборщика мусора. Сборщик будет работать только когда явно вызывается, пока вызов не перезапустит его.
  • «restart«: перезапускает автоматическое выполнение сборщика мусора.
  • «count«: возвращает полный объем памяти, используемый Lua, в килобайтах. Значение имеет дробную часть, так что умножение его на 1024 даст точное число байт, используемых Lua (за исключением переполнений).
  • «step«: выполняет шаг по сборке мусора.
    «Размером» шага управляет аргумент arg. С нулевым значением сборщик будет выполнять один основной (неделимый) шаг.
    Для ненулевых значений сборщик будет выполнять свою работу так, как если бы такое количество памяти (в килобайтах) было выделено от Lua. Возвращает true, если шаг заканчивает цикл сборки мусора.
  • «setpause«: устанавливает аргумент arg как новое значение для паузы в работе сборщика мусора (смотрите ). Возвращает предыдущее значение для pause.
  • «setstepmul«: устанавливает аргумент arg как новое значение для множителя шага сборщика мусора (смотрите ).
    Возвращает предыдущее значение шага.
  • «isrunning«: возвращает логическое значение, которое сообщает, запущен ли сборщик мусора (то есть, он не остановлен).

t

for i,v in ipairs(t) do body end

1,t2,t

t__pairsttnil

for k,v in pairs(t) do body end

t

Операторы языка

Набор условных операторов и циклов довольно типичен:

-- условные операторы (ветки else может не быть)
if a == 0 then
  print("a is zero")
else
  print("a is not zero")
end

-- сокращенная форма if/elseif/end (вместо switch/case)
if a == 0 then
  print("zero")
elseif a == 1 then
  print("one")
elseif a == 2 then
  print("two")
else
  print("other")
end

-- цикл со счетчиком
for i = 1, 10 do 
  print(i)
end

-- цикл с предусловием
b = 5
while b > 0 do
  b = b - 1
end

-- цикл с постусловием
repeat
  b = b + 1
until b >= 5

ПОДУМАЙТЕ: что может означать цикл ?

В выражениях можно использовать такие вот операторы над переменными:

* присваивание: x = 0
* арифметические: +, -, *, /, % (остаток от деления), ^ (возведение в степень)
* логические: and, or, not
* сравнение: >, <, ==, <=, >=, ~= (не-равно, да-да, вместо привычного «!=»)
* конкатенация строк (оператор «..»), напр.: s1=»hello»; s2=»world»; s3=s1..s2
* длина/размер (оператор #): s=»hello»; a = #s (‘a’ будет равно 5).
* получение элемента по индексу, напр.: s

Битовых операций в языке долгое время не было, но в версии 5.2 появилась библиотека bit32, которая их реализует (как функции, не как операторы).

Между Lua и не-Lua

ВНИМАНИЕ: эту часть рекомендуется читать людям со знанием языка C. А если нам недостаточно функциональности стандартных библиотек? Если у нас есть наша программа на C, а мы хотим вызывать ее функции из Lua? Для этого есть очень простой механизм

А если нам недостаточно функциональности стандартных библиотек? Если у нас есть наша программа на C, а мы хотим вызывать ее функции из Lua? Для этого есть очень простой механизм.

Допустим, мы хотим создать свою функцию, которая возвращает случайное число (в Lua есть math.random(), но мы хотим поучиться). Нам придется написать вот такой код на C:

#include <lua.h>
#include <lauxlib.h>
#include <time.h>

/* собственно, что делать при вызове `rand(from, to)` */
static int librand_rand(lua_State *L) {
	int from, to;
	int x;

	from = lua_tonumber(L, 1); /* первый параметр функции */
	to = lua_tonumber(L, 2); /* второй параметр функции */

	x = rand() % (to - from + 1) + from;

	lua_pushnumber(L, x); /* возвращаемое значение */
	return 1; /* возвращаем только один аргумент */
}

/* в Lua "rand" соответствует нашей функции librand_rand() */
static const luaL_reg R[] = {
	{"rand", librand_rand}, 
	{NULL, NULL} /* конец списка экспортируемых функций */
};

/* вызывается при загрузке библиотеку */
LUALIB_API int luaopen_librand(lua_State *L) {
	luaL_openlib(L, "librand", R, 0);
	srand(time(NULL));
	return 1; /* завершаемся успешно */
}

Т.е. Lua предоставляет нам функции для работы с типами данных, для получения аргументов функций и возврата результатов. Функций очень мало, и они довольно простые. Теперь мы собираем нашу библиотеку как динамическую, и можем использовать функцию rand():

random = require("librand") -- загружаем библиотеку

print(random.rand(1, 100))
print(random.rand(0, 1))

А если мы хотим вызывать код, написанный на Lua из наших программ? Тогда наши программы должны создавать виртуальную машину Lua, в которой и будут выполняться Lua-скрипты. Это намного проще:

#include "lua.h"
#include "lauxlib.h"

int main() {
	lua_State *L = lua_open(); // создаем виртуальную машину Lua
	luaL_openlibs(L); // загружаем стандартные библиотеку
	luaL_dofile(L, "rand.lua"); // выполняем скрипт
	lua_close(L); // закрываем Lua
	return 0;
}

Примеры простых циклов

--lua
for i = 1, 3 do          -- шаг не указан, по умолчанию равен 1
  msg (i)
end
-- увидим: 1 2 3
--lua
for i = 4, 8, 2 do       -- шаг 2
  msg ("Миша съел " .. i .. " яблок(а)")
end
-- увидим: 4 6 8
--lua
-- назад, с шагом -1
local a = 4
local b = 2
local s = -1
for j = a, b, s do
   log ("Считаем назад: " .. j)
end
log ("Закончили счёт")
-- увидим: 4 3 2 закончили
--lua
-- вперед, с шагом 1, используем break
for k = 2, 6 do
  log ("Считаем вперед: " .. k .. "A")
  if k == 4 then   -- если переменная 'k' равна 4
      break   -- прервать цикл
  end   
  log ("Считаем вперед: " .. k .. "Б")
end
log ("Закончили счёт")
-- увидим: 2А 2Б 3А 3Б 4А Закончили
--lua
-- цикл с нецелыми числами.
for i = 0.1, 0.7, 0.15 do
   log (i)
end

6.8 – Средства ввода/вывода

ioioio.stdinio.stdoutio.stderrnilnilerrno

io.open (filename )

modenilmode

  • «r«: режим чтения (по умолчанию);
  • «w«: режим записи;
  • «a«: режим добавления;
  • «r+«: режим обновления, все предыдущие данные сохраняются;
  • «w+«: режим обновления, все предыдущие данные удаляются;
  • «a+«: режим обновления с добавлением, предыдущие данные сохраняются, запись допускается только в конец файла.

modeb

l

for c in file:lines(1) do body end

file:read (...)

filenil

  • «n«: считывает число и возвращает его как число с плавающей запятой или целое число, следуя лексическим соглашениям Lua. (Число может иметь перед собой пробелы и знак.)
    Этот формат всегда считывает самую длинную входную последовательность, которая является для числа допустимым префиксом; если этот префикс не формирует
    допустимое число (например, пустая строка, «0x«, или «3.4e-«), он отбрасывается и функция возвращает nil.
  • «a«: считывает весь файл, начиная с текущей позиции. По окончании файла, возвращает пустую строку.
  • «l«: считывает следующую строку, пропуская символ конца строки; возвращает nil по окончании файла. Это формат по умолчанию.
  • «L«: считывает следующую строку, сохраняя символ конца строки (если он присутствует); возвращает nil по окончании файла.
  • number: считывает строку вплоть до указанного числа байт (number — число), возвращая nil по завершении файла.
    Если number является нулем, то ничего не считывается и возвращается пустая строка, или nil по завершении файла.

lL

file:seek (])

offsetwhence

  • «set«: базовое значение равно 0 (начало файла);
  • «cur«: базовым значением является текущая позиция;
  • «end«: базовым значением является конец файла;

seekseeknilwhence"cur"offsetfile:seek()file:seek("set")file:seek("end")

file:setvbuf (mode )

  • «no«: нет буферизации; результат любой выходной операции появляется немедленно.
  • «full«: полная буферизация; выходная операция выполняется только когда буфер полон, или когда буферы файла явно сбрасываются (смотрите ).
  • «line«: строчная буферизация; выход буферизуется до тех пор, пока на выходе не появится символ «новая строка» или имеется любой ввод из некоторых специальных файлов (таких как терминальное устройство).

size

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: