Видео ролики бесплатно онлайн

Смотреть в хорошем качестве hd видео

Официальный сайт filipoc 24/7/365

Смотреть видео бесплатно

28.02.11 17:13 kstep

CodingВведение в Lua для программистов — часть 2.3

Немного раньше я показал работу с функциями. Теперь я расскажу о типах userdata и thread, а так же затрону тему области видимости переменных.



Франшиза



Тип данных userdata стоит несколько особняком. По сути это аватар произвольной C-структуры в мире Lua. Или, если угодно, своеобразная франшиза, бренд, под которым в Lua видны кастомные типы данных. Строго говоря нет такого одного отдельного типа данных — userdata, есть множество различных разнородных кастомных типов данных, которые создаются либо в C-библиотеках, либо в хост-приложении, которое пользует Lua (не забываем, что Lua очень часто используется не как самостоятельный интерпретатор, а как библиотека, прилинкованная к «большому» приложению, и вот это приложение может создать произвольное окружение для выполняемых в его рамках Lua-скриптов; оно и будет хостом для Lua-программ). В Lua все такие кастомные типы (обычно это C-шные struct-ы, но это необязательно) видны как один тип — userdata, хотя и природа данных под этим типом может быть совершенно разная.

Примером типа userdata может, например, послужить объект screen в Awesome:

1
2
3
4
5
6
7

$ awesome-client
awesome# return screen[1]
    string "userdata: 0x9eb54d0"
awesome# return type(screen[1])
    string "userdata"
 


В данном случае хост-приложение Awesome передаёт в Lua-окружение специальную таблицу-массив screen, элементы которых содержать объекты, представляющие физический экран. Хотя внешне эти элементы видны как объекты типа userdata, фактически это объекты типа screen, предоставляющие интерфейс к физическому экрану: его разрешение, рабочую область за вычетом зон, занятых виджетами самого WM и порядковый номер экрана. Точно так же Awesome определяет несколько других типов данных в Lua для манипуляции с запущенными приложениями, изображениями и т.д. Подробнее можно про этот зоопарк почитать в официальной документации.

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

Клубок нитей



Lua поддерживает исполнение кооперативных потоков, для этого есть специальная библиотека coroutine. Если честно я сомневаюсь, стоит ли рассказывать сейчас про все её фичи, потому что сопрограммы и мультритрединг (в любом виде, в том числе и кооперативный) — это тема отдельной большой статьи, которую я ещё напишу. Поэтому здесь я просто упомяну, что такая библиотека есть, а тем, кому не в терпёж, (и позволяет теоретическая и практическая подготовка) могут прочитать про неё в документации к Lua прямо сейчас. Если кратко, то объекты типа thread создаются функциями из библиотеки coroutine, представляют один поток выполнения и предоставляют интерфейс для манипуляции с этим потоком.

Переменные под прикрытием



А теперь так же кратенько о переменных. Переменные по области видимости в Lua делятся на локальные и глобальные. Все переменные, которые создаются в программе, являются глобальными, если особо не заявлено обратное:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

-- создаём переменную b
b = 10

-- здесь изменяется переменная b
function setb()
    b = 20
end

-- здесь изменяется переменная a
function seta()
    a = 30
end

-- выведет nil и 10
print(a, b)
seta()
setb()
-- выведет 30 и 20
print(a, b)
 


Как видите обе переменные a и b глобальны, хотя вне тела функции создана только переменная b.

Локальные переменные объявляются с помощью ключевого слова local, закрывая по необходимости глобальные переменные с теми же именами:

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

function seta()
    -- здесь a пока что глобальная
    print("before local", a)
    a = 20
   
    -- а здесь она локальная
    local a
    print("after local", a)
    a = 30
    print("after local assignment", a)
end

-- глобальная a
a = 10

-- выведет 10
print(a)

--[[ выведет:
before local 10
after local nil
after local assignment 30
]]

seta()

-- выведет 20
print(a)
 


Оператор local действует в пределах текущего блока операторов, при этом действие его начинается в момент определения переменной с этим ключевым словом (как видно в примере функция seta() могла модифицировать глобальную переменную до тех пор, пока она не была перекрыта локальной, объявленной оператором local).

Кроме того можно совместить присваивание переменной значения с её объявлением через local.

Локальные переменные могут быть созданы не только в пределах функции, но и в пределах любого блока операторов:

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

somevar = 10

-- локальная переменная в if-е:
if true then
    local somevar = 20
    print(somevar) -- выведет 20
end

-- локальная переменная в for:
for i = 1, 10 do
    local somevar = i + 10
    -- выведет числа от 11 до 20
    print(somevar)
end

-- локальная переменная в while-е:
while true do
    local somevar = 30
    print(somevar) -- выведет 30

    break -- превентивный выход из цикла
end

-- выведет 10
print(somevar)
 


Если хочется локальной переменной только в некотором куске кода, и не хочется объявлять циклов и функций, то можно воспользоваться универсальными операторными скобками do ... end:

1
2
3
4
5
6
7
8
9
10
11
12

othervar = 100

do
    local othervar = 50
    -- будет 50
    print(othervar)
end

-- будет 100
print(othervar)
 


Локальными могут быть и функции, ведь объявление функции это всего навсего присваивание объекта типа функция некоторой переменной:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

function outer()
    -- то же, что и
    -- local inner; inner = function() end
    local function inner()
    end
    print(inner)

    function inner2()
    end
end

-- выведет что-то вроде function: 0x934da48
-- (функция inner)
outer()

-- функция inner не попадёт в глобальную область видимости:
-- выведет nil
print(inner)

-- но функция inner2 будет видна снаружи:
-- выведет что-то вроде function: 0x934d610
print(inner2)
 


Локальные переменные имеют лексическую область видимости:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

a = 10
function geta()
    print(a)
end

function seta()
    local a = 20
    geta()
end

-- выведет 10, потому что локальная a из seta()
-- лексически заперта в функции seta(), так что geta()
-- увидит только глобальную a.
seta()
 


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

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

Итог: мы наскоро познакомились с двумя последними типами данных — userdata и thread, узнали про локальные переменные (которые объявляются оператором local и имеют лексическую область видимости) и универсальный операторный блок do ... end. Кроме того внимательных читателей ожидал бонус в виде оператора break для досрочного выхода из цикла.

В следующей статье я хочу устроить интерлюдию, в которой собираюсь привести пример рабочей программы на основе уже изложенного материала. Какой именно пример показать я пока ещё не придумал, поэтому у читателей есть шанс предложить свои варианты. Или может у кого уже есть какие-то наброски по тексту статей? Идеи прошу в комменты!



neqste 28.02.11 19:59 # +3
Очень часто сталкиваюсь с данным языком программирования в играх. Пример тому ragnarok online. спасибо за интересную статью
ascrazy 01.03.11 00:02 # +0
Может стоит сделать что нить типа глобальной навигации по всем статьям серии?
vvorth 01.03.11 08:24 # +0
Да, было бы хорошо в каждую статью включить ссылки на все предыдущие, а можно даже обновлять ранние, добавляя в них ссылки на все следующие =.)
kstep 01.03.11 14:20 # +2
Дык, вот же.
GalS 02.03.11 11:26 # +2
мультритрединг
многопоточность?
в if-е:
...
в for:
...
в while-е:
нет однообразности

Посты Комментарии
Последние посты
    Посты Комментарии
    Последние комментарии
      Посты Комментарии
      Изменения
        Посты Комментарии Изменения Черновики Избранное
        Черновики (все)
          Посты Комментарии Изменения Черновики Избранное
          Избранное (всё)
            Посты Комментарии Изменения Черновики Избранное
            Лучшие блоги (все 165)
            Топ пользователей Топ блогов
            Топ пользователей Топ блогов
            Элита (все 3368 из 238 городов)
            Топ пользователей Топ блогов
            welinux.ru

            Смотреть онлайн бесплатно

            Онлайн видео бесплатно


            Смотреть русское с разговорами видео

            Online video HD

            Видео скачать на телефон

            Русские фильмы бесплатно

            Full HD video online

            Смотреть видео онлайн

            Смотреть HD видео бесплатно

            School смотреть онлайн