summaryrefslogtreecommitdiffhomepage
path: root/ru-ru/lua-ru.html.markdown
blob: 3fd478ef834a1231f999e35851a95d9c7bd56548 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
---
language: lua
filename: learnlua-ru.lua
contributors:
    - ["Tyler Neylon", "http://tylerneylon.com/"]
translators:
    - ["Max Solomonov", "https://vk.com/solomonovmaksim"]
    - ["Max Truhonin", "https://vk.com/maximmax42"]	
lang: ru-ru
---

```lua
-- Два дефиса начинают однострочный комментарий.

--[[
    Добавление двух квадратных скобок
    делает комментарий многострочным.
--]]
--------------------------------------------------------------------------------
-- 1. Переменные, циклы и условия.
--------------------------------------------------------------------------------

num = 42  -- Все числа являются типом double.
--[[ 
    Не волнуйся, 64-битные double имеют 52 бита
    для хранения именно целочисленных значений;
    точность не является проблемой для
    целочисленных значений, занимающих меньше
    52 бит.
--]]

s = 'walternate'  -- Неизменные строки как в Python.
t = "Двойные кавычки также приветствуются"
u = [[ Двойные квадратные скобки
       начинают и заканчивают
       многострочные значения.]]
t = nil  -- Удаляет определение переменной t; Lua имеет мусорку.

-- Циклы и условия имеют ключевые слова, такие как do/end:
while num < 50 do
  num = num + 1  -- Здесь нет ++ или += операторов.
end

-- Условие "если":
if num > 40 then
  print('больше 40')
elseif s ~= 'walternate' then  -- ~= обозначает "не равно".
  -- Проверка равенства это == как в Python; ok для строк.
  io.write('не больше 40\n')  -- По умолчанию стандартный вывод.
else
  -- По умолчанию переменные являются глобальными.
  thisIsGlobal = 5  -- Стиль CamelСase является общим.

  -- Как сделать локальную переменную:
  local line = io.read()  -- Считывает введённую строку.

  -- Конкатенация строк использует .. оператор:
  print('Зима пришла, ' .. line)
end

-- Неопределённые переменные возвращают nil.
-- Этот пример не является ошибочным:
foo = anUnknownVariable  -- Теперь foo = nil.

aBoolValue = false

-- Только значения nil и false являются ложными; 0 и '' являются истинными!
if not aBoolValue then print('это значение ложно') end

--[[
     Для 'or' и 'and' действует принцип "какой оператор дальше, 
     тот и применяется". Это действует аналогично a?b:c 
     операторам в C/js:
--]]
ans = aBoolValue and 'yes' or 'no'  --> 'no'

karlSum = 0
for i = 1, 100 do  -- Здесь указан диапазон, ограниченный с двух сторон.
  karlSum = karlSum + i
end

-- Используйте "100, 1, -1" как нисходящий диапазон:
fredSum = 0
for j = 100, 1, -1 do fredSum = fredSum + j end

-- В основном, диапазон устроен так: начало, конец[, шаг].

-- Другая конструкция цикла:
repeat
  print('путь будущего')
  num = num - 1
until num == 0

--------------------------------------------------------------------------------
-- 2. Функции.
--------------------------------------------------------------------------------

function fib(n)
  if n < 2 then return n end
  return fib(n - 2) + fib(n - 1)
end

-- Вложенные и анонимные функции являются нормой:
function adder(x)
  -- Возращаемая функция создаётся когда adder вызывается, тот в свою очередь
  -- запоминает значение переменной x:
  return function (y) return x + y end
end
a1 = adder(9)
a2 = adder(36)
print(a1(16))  --> 25
print(a2(64))  --> 100

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

x, y, z = 1, 2, 3, 4
-- Теперь x = 1, y = 2, z = 3, и 4 просто отбрасывается.

function bar(a, b, c)
  print(a, b, c)
  return 4, 8, 15, 16, 23, 42
end

x, y = bar('zaphod')  --> выводит "zaphod  nil nil"
-- Теперь x = 4, y = 8, а значения 15..42 отбрасываются.

-- Функции могут быть локальными и глобальными. Эти строки делают одно и то же:
function f(x) return x * x end
f = function (x) return x * x end

-- Эти тоже:
local function g(x) return math.sin(x) end
local g = function(x) return math.sin(x) end
-- Equivalent to local function g(x)..., except referring to g in the function
-- body won't work as expected.
local g; g  = function (x) return math.sin(x) end
-- the 'local g' decl makes g-self-references ok.

-- Trig funcs work in radians, by the way.

-- Вызов функции с одним текстовым параметром не требует круглых скобок:
print 'hello'  -- Работает без ошибок.

-- Вызов функции с одним табличным параметром так же не требуют круглых скобок (про таблицы в след.части):
print {} -- Тоже сработает.

--------------------------------------------------------------------------------
-- 3. Таблицы.
--------------------------------------------------------------------------------

-- Таблицы = структура данных, свойственная только для Lua; это ассоциативные массивы.
-- Similar to php arrays or js objects, they are hash-lookup dicts that can
-- also be used as lists.

-- Using tables as dictionaries / maps:

-- Dict literals have string keys by default:
t = {key1 = 'value1', key2 = false}

-- String keys can use js-like dot notation:
print(t.key1)  -- Печатает 'value1'.
t.newKey = {}  -- Добавляет новую пару ключ-значение.
t.key2 = nil   -- Удаляет key2 из таблицы.

-- Literal notation for any (non-nil) value as key:
u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
print(u[6.28])  -- пишет "tau"

-- Key matching is basically by value for numbers and strings, but by identity
-- for tables.
a = u['@!#']  -- Теперь a = 'qbert'.
b = u[{}]     -- We might expect 1729, but it's nil:
-- b = nil since the lookup fails. It fails because the key we used is not the
-- same object as the one used to store the original value. So strings &
-- numbers are more portable keys.

-- A one-table-param function call needs no parens:
function h(x) print(x.key1) end
h{key1 = 'Sonmi~451'}  -- Печатает 'Sonmi~451'.

for key, val in pairs(u) do  -- Итерация цикла с таблицей.
  print(key, val)
end

-- _G - это таблица со всеми глобалями.
print(_G['_G'] == _G)  -- Печатает 'true'.

-- Using tables as lists / arrays:

-- List literals implicitly set up int keys:
v = {'value1', 'value2', 1.21, 'gigawatts'}
for i = 1, #v do  -- #v is the size of v for lists.
  print(v[i])  -- Indices start at 1 !! SO CRAZY!
end
-- A 'list' is not a real type. v is just a table with consecutive integer
-- keys, treated as a list.

--------------------------------------------------------------------------------
-- 3.1 Мета-таблицы и мета-методы.
--------------------------------------------------------------------------------

-- A table can have a metatable that gives the table operator-overloadish
-- behavior. Later we'll see how metatables support js-prototypey behavior.

f1 = {a = 1, b = 2}  -- Represents the fraction a/b.
f2 = {a = 2, b = 3}

-- Это не сработает:
-- s = f1 + f2

metafraction = {}
function metafraction.__add(f1, f2)
  local sum = {}
  sum.b = f1.b * f2.b
  sum.a = f1.a * f2.b + f2.a * f1.b
  return sum
end

setmetatable(f1, metafraction)
setmetatable(f2, metafraction)

s = f1 + f2  -- вызывает __add(f1, f2) на мета-таблице f1

-- f1, f2 have no key for their metatable, unlike prototypes in js, so you must
-- retrieve it as in getmetatable(f1). The metatable is a normal table with
-- keys that Lua knows about, like __add.

-- But the next line fails since s has no metatable:
-- t = s + s
-- Class-like patterns given below would fix this.

-- An __index on a metatable overloads dot lookups:
defaultFavs = {animal = 'gru', food = 'donuts'}
myFavs = {food = 'pizza'}
setmetatable(myFavs, {__index = defaultFavs})
eatenBy = myFavs.animal  -- работает! спасибо, мета-таблица.

--------------------------------------------------------------------------------
-- Direct table lookups that fail will retry using the metatable's __index
-- value, and this recurses.

-- An __index value can also be a function(tbl, key) for more customized
-- lookups.

-- Values of __index,add, .. are called metamethods.
-- Full list. Here a is a table with the metamethod.

-- __add(a, b)                     для a + b
-- __sub(a, b)                     для a - b
-- __mul(a, b)                     для a * b
-- __div(a, b)                     для a / b
-- __mod(a, b)                     для a % b
-- __pow(a, b)                     для a ^ b
-- __unm(a)                        для -a
-- __concat(a, b)                  для a .. b
-- __len(a)                        для #a
-- __eq(a, b)                      для a == b
-- __lt(a, b)                      для a < b
-- __le(a, b)                      для a <= b
-- __index(a, b)  <fn or a table>  для a.b
-- __newindex(a, b, c)             для a.b = c
-- __call(a, ...)                  для a(...)

--------------------------------------------------------------------------------
-- 3.2 Class-like tables and inheritance.
--------------------------------------------------------------------------------

-- Classes aren't built in; there are different ways to make them using
-- tables and metatables.

-- Explanation for this example is below it.

Dog = {}                                   -- 1.

function Dog:new()                         -- 2.
  local newObj = {sound = 'woof'}          -- 3.
  self.__index = self                      -- 4.
  return setmetatable(newObj, self)        -- 5.
end

function Dog:makeSound()                   -- 6.
  print('I say ' .. self.sound)
end

mrDog = Dog:new()                          -- 7.
mrDog:makeSound()  -- 'I say woof'         -- 8.

-- 1. Dog acts like a class; it's really a table.
-- 2. "function tablename:fn(...)" is the same as
--    "function tablename.fn(self, ...)", The : just adds a first arg called
--    self. Read 7 & 8 below for how self gets its value.
-- 3. newObj will be an instance of class Dog.
-- 4. "self" is the class being instantiated. Often self = Dog, but inheritance
--    can change it. newObj gets self's functions when we set both newObj's
--    metatable and self's __index to self.
-- 5. Reminder: setmetatable returns its first arg.
-- 6. The : works as in 2, but this time we expect self to be an instance
--    instead of a class.
-- 7. Same as Dog.new(Dog), so self = Dog in new().
-- 8. Same as mrDog.makeSound(mrDog); self = mrDog.

--------------------------------------------------------------------------------

-- Inheritance example:

LoudDog = Dog:new()                           -- 1.

function LoudDog:makeSound()
  local s = self.sound .. ' '                 -- 2.
  print(s .. s .. s)
end

seymour = LoudDog:new()                       -- 3.
seymour:makeSound()  -- 'woof woof woof'      -- 4.

--------------------------------------------------------------------------------
-- 1. LoudDog gets Dog's methods and variables.
-- 2. self has a 'sound' key from new(), see 3.
-- 3. Same as "LoudDog.new(LoudDog)", and converted to "Dog.new(LoudDog)" as
--    LoudDog has no 'new' key, but does have "__index = Dog" on its metatable.
--    Result: seymour's metatable is LoudDog, and "LoudDog.__index = Dog". So
--    seymour.key will equal seymour.key, LoudDog.key, Dog.key, whichever
--    table is the first with the given key.
-- 4. The 'makeSound' key is found in LoudDog; this is the same as
--    "LoudDog.makeSound(seymour)".

-- If needed, a subclass's new() is like the base's:
function LoudDog:new()
  local newObj = {}
  -- set up newObj
  self.__index = self
  return setmetatable(newObj, self)
end

--------------------------------------------------------------------------------
-- 4. Модули.
--------------------------------------------------------------------------------


--[[ I'm commenting out this section so the rest of this script remains
--   runnable.
```

```lua
-- Suppose the file mod.lua looks like this:
local M = {}

local function sayMyName()
  print('Hrunkner')
end

function M.sayHello()
  print('Why hello there')
  sayMyName()
end

return M

-- Another file can use mod.lua's functionality:
local mod = require('mod')  -- Run the file mod.lua.

-- require is the standard way to include modules.
-- require acts like:     (if not cached; see below)
local mod = (function ()
  <contents of mod.lua>
end)()
-- It's like mod.lua is a function body, so that locals inside mod.lua are
-- invisible outside it.

-- This works because mod here = M in mod.lua:
mod.sayHello()  -- Says hello to Hrunkner.

-- This is wrong; sayMyName only exists in mod.lua:
mod.sayMyName()  -- error

-- require's return values are cached so a file is run at most once, even when
-- require'd many times.

-- Suppose mod2.lua contains "print('Hi!')".
local a = require('mod2')  -- Prints Hi!
local b = require('mod2')  -- Doesn't print; a=b.

-- dofile is like require without caching:
dofile('mod2')  --> Hi!
dofile('mod2')  --> Hi! (runs again, unlike require)

-- loadfile loads a lua file but doesn't run it yet.
f = loadfile('mod2')  -- Calling f() runs mod2.lua.

-- loadstring is loadfile for strings.
g = loadstring('print(343)')  -- Returns a function.
g()  -- Prints out 343; nothing printed before now.

--]]

```
## References

I was excited to learn Lua so I could make games
with the <a href="http://love2d.org/">Love 2D game engine</a>. That's the why.

I started with <a href="http://nova-fusion.com/2012/08/27/lua-for-programmers-part-1/">BlackBulletIV's Lua for programmers</a>.
Next I read the official <a href="http://www.lua.org/pil/contents.html">Programming in Lua</a> book.
That's the how.

It might be helpful to check out the <a href="http://lua-users.org/files/wiki_insecure/users/thomasl/luarefv51.pdf">Lua short
reference</a> on lua-users.org.

The main topics not covered are standard libraries:

* <a href="http://lua-users.org/wiki/StringLibraryTutorial">string library</a>
* <a href="http://lua-users.org/wiki/TableLibraryTutorial">table library</a>
* <a href="http://lua-users.org/wiki/MathLibraryTutorial">math library</a>
* <a href="http://lua-users.org/wiki/IoLibraryTutorial">io library</a>
* <a href="http://lua-users.org/wiki/OsLibraryTutorial">os library</a>

By the way, the entire file is valid Lua; save it
as learn.lua and run it with "lua learn.lua" !

This was first written for tylerneylon.com, and is
also available as a <a href="https://gist.github.com/tylerneylon/5853042">github gist</a>. Have fun with Lua!