1

Тема: Передать структуру в функцию.

Всем доброго времени суток. У меня такой вопрос. Нигде не смог найти, возможно ли вообще в скрипте Qlua передать в функцию структуру в качестве параметра и внутри функции с ней работать? На том же Си это делается указателем, а тут я вообще ничего такого не нашел. Впрочем здесь же точно такая же чехарда и с типами данных, ну не могу я привыкнуть к тому, что тип данных определяется сам...

2 (2022-08-12 10:50:12 отредактировано swerg)

Re: Передать структуру в функцию.

Lua очень клёвый и компактный язык.
В нем по сути всего две разновидности групп типов переменных: простые переменные (number/string и т.п.) и таблицы. При этом для таблиц доступен синтаксис "а-ля структура".
Стоит тут же сразу отметить, что "переменные простых типов" на самом деле поля глобальной таблицы, просто синтаксически её можно не указывать smile
Т.е., вообще говоря, всё в Lua - таблицы. И всё. Изучить надо всего  1 тип. Классно же, правда?

Таблица в стиле "структура":

t = {}
t.price = 5
t.qty = 100

Такой синтаксис выглядит как заполнение структуры, правда же? Здорово.
И обращаться можно в стиле структур:

vol = t.price * t.qty

Однако на самом деле t в вышеприведенном коде - это таблица с двумя элементами:

t["price"]
t["qty"]

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

vol = t["price"] * t["qty"]

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

function GetVol(q)
  return q.price * q.qty
end

t = {}
t.price = 5
t.qty = 100

vol = GetVol(t)

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

Например

function GetVol(q)
  q.price = 6
  return q.price * q.qty
end

t = {}
t.price = 5
t.qty = 100

print("Price1=", t.price)
print("Vol=", GetVol(t))
print("Price2=", t.price)

напечатает

Price1= 5
Vol= 600
Price2= 6
  <-- значение поля переданной таблицы изменено внутри функции!

Можете скопировать этот код сюда и убедиться:
[url]https://qlua.ru/demo/[/url]


PS
Вообще, конечно, хорошо бы почитать книжку любую простую по Lua. Это ж недолго. Зато вот эти все вопросы сразу отпадут, тем более что язык несколько самобытен местами.

3

Re: Передать структуру в функцию.

Lua очень клёвый и компактный язык.

Не спорю. НО! Когда годами вдалбливали типы данных я уже на подкорке мозга это записано... И вдруг на тебе и никаких типов smile)) Ну все это лирика, это мои личные проблемы с переключением...
Написали все очень интересно. Из всего сказанного делаю вывод, в функцию тупо можно передавать простую переменную number/string и т.п. С этим без проблем. А вот если у нас присутствует таблица (структура, массив, а это в луа тоже самое что и таблица), то если выражаться сишными терминами, то в функцию передается автоматически указатель на первый элемент таблицы. Причем как я понимаю, не важно как она объявлена, как глобальная или локальная?

книжку любую простую по Lua

с удовольствием, но найти бы ее еще smile Проблема даже не с поиском, проблема в том, что я понятия не имею, LUA, тот что оригинал, и QLua, тот что используется для написания скриптов в QUIK это вообще одно и тоже или все таки это разные языки(само собой если закрыть глаза на специфические функции для работы с QUIK, понятное дело их в оригинале точно не будет)? Если посоветуете ту самую простенькую книжечку по Qlua для QUIK буду благодарен. Изучать сам язык досконально мне нет необходимости, нужны поверхностные знания, типа работы с файлами на создание/запись/чтение. Похоже это самый максимум что мне нужен smile

4

Re: Передать структуру в функцию.

В QUIK самый обычный Lua, в который добавлены некоторые функции. Вот и все. ничего "другого" там нет.
Где-то когда-то мне попалась шикарная презенташка типа "Lua for C++ programmers", там прям прекрасно и очень кратко все было изложено.
Увы, сейчас не смог нагуглить, как-нибудь потом.

А так - достаточно нагуглить любое "введение в lua" - вот и все.
Впрочем, оригинальная документация весьма проста, прочитать её не сложно.
[url]https://www.lua.org/manual/5.4/[/url]

Есть даже на русский перевод (по 5.3 версии, но различий не заметите)
[url]http://lua.org.ru/contents_ru.html[/url]

5

Re: Передать структуру в функцию.

Есть даже на русский перевод

Да, это есть у меня. Но напрягает синтаксис, например оператор присваивания ::=, еще обилие абсолютно нигде не описанных и мне не знакомых ';' '=' ',' и прочих конструкций... и все без примеров smile

6

Re: Передать структуру в функцию.

dark184 пишет:

например оператор присваивания ::=, еще обилие абсолютно нигде не описанных и мне не знакомых ';' '=' ',' и прочих конструкций...

Это не "оператор присваивания", это формальное описание синтаксиса.
Читается без привычки и знаний сложновато, согласен.

Впрочем, материала по Lua в инете - вагоны.

7 (2022-08-12 19:24:02 отредактировано dark184)

Re: Передать структуру в функцию.

Спасибо. Тут накопал маленькую библиотеку [url]https://disce.ru/little-library/lua[/url] smile Далеко не все, но по крайней мере с примерами и вменяемым описанием.
Вобщем с передачей массива в функцию разобрался. Все отлично работает. Возник еще вопрос, не допенькал пока сам.
Создаю массив и вызываю функцию

    Column_Table =    {
                    {7,3},
                    {"Инструмент",QTABLE_STRING_TYPE,15},
                    {"Шаг цены",QTABLE_DOUBLE_TYPE, 15},
                    {"Точность",QTABLE_INT_TYPE, 15},
                    {"High BB",QTABLE_DOUBLE_TYPE, 15},
                    {"Mid BB",QTABLE_DOUBLE_TYPE, 15},
                    {"Low BB, руб.",QTABLE_DOUBLE_TYPE, 15},
                    {"Bollinger Ind",QTABLE_STRING_TYPE, 15},
    } 
    Table_init(Column_Table)


Которой передаю массив

function Table_init(t)
    local Table = AllocTable()
        for j=2,t[1][1]+1,1 do
            AddColumn(Table,j-1,t[j][1], true, t[j][2], t[j][3])
        end
    CreateWindow(Table)
    SetWindowCaption(Table, "Отладочная таблица")
    InsertRow(Table, -1)

Видно, что в массив пришлось впихнуть количество строк, а в цикле читать из переданного массива. Все в принципе работает без нареканий. НО! Могу ли я получить количество строк в этом массиве уже в функции?
честно говоря мозг кипит уже... В си нельзя вот прямо так взять и создать массив из разных типов данных... Хотя... Может быть и можно... Но видимо это будет называться структурой smile

8

Re: Передать структуру в функцию.

dark184 пишет:

НО! Могу ли я получить количество строк в этом массиве уже в функции?

Разумеется.
Для этого есть даже несколько способов.
Но вот беда: ни один из них не дает верного результата в общем случае. Такая вот фигня smile
Я несколько плаваю в этой теме, рассказать не возьмусь.
Но гугл знает точно, как и документация в разделе про таблицы.
Плюс не всегда требуется знать количество элементов, если задача просто их проитерировать все в цикле. См. for ipairs(t) и for pairs(t)
Иногда именно проитерировав в цикле лишь и можно точно узнать количество элементов. Где-то было на форуме квика.

9 (2022-08-14 13:21:45 отредактировано dark184)

Re: Передать структуру в функцию.

Для этого есть даже несколько способов.

Походу я нашел еще способ.

function Table_init(t)

    local i = 0
    local Table = AllocTable()
        for i=1,#t,1 do
            AddColumn(Table, i, t[i][1], true, t[i][2], t[i][3])
        end

    CreateWindow(Table)
    SetWindowCaption(Table, "Отладочная таблица")
    InsertRow(Table, -1)
    
    SetCell(Table,1,4,tostring (#t))

return Table

end

#t почему то возвращает именно количество строк, а не всю длину массива. Массив у меня двумерный 18 строк и 3 столбца. Я ожидал значение 54, а по факту получил 18(точнее 19 пока не убрал ставшую не нужной первую строку). Не то что я недоволен, просто непонятно почему?
В принципе именно это мне и нужно было.

10 (2022-08-14 17:26:20 отредактировано swerg)

Re: Передать структуру в функцию.

dark184 пишет:

#t почему то возвращает именно количество строк, а не всю длину массива. Массив у меня двумерный 18 строк и 3 столбца. Я ожидал значение 54

#t возвращает количество элементов таблицы t.  В ней 18 элементов.
А то, что каждый элемент t тоже в свою очередь таблица - так это отдельная история.

Вот пример:

t = {
  {"A", 5, "b", 6},
  {"z", 5},
  {"#", 1, 6},
}

print("#t=", #t)
print("#t[1]=", #t[1])
print("#t[2]=", #t[2])
print("#t[3]=", #t[3])

Он вернет:

#t=    3
#t[1]=    4
#t[2]=    2
#t[3]=    3

11 (2022-08-14 18:10:57 отредактировано dark184)

Re: Передать структуру в функцию.

Спасибо, дошло. Теперь я понял в чем была моя вторая ошибка smile Сначала просто угадал, потом решил посчитать количество столбцов smile Не вышло. Теперь понял почему smile Как же все не привычно sad
Если для того же Си здесь(переменная целая, неважно знаковая или нет)

if signal then
    message("Условие верное")
else
    message("Условие неверное")
end

если в переменной signal любое число отличное от нуля, он считает условие true. Если 0 то false. Здесь такая запись не катит, всегда true, нужно явно сравнивать sad

12 (2022-08-15 10:07:21 отредактировано swerg)

Re: Передать структуру в функцию.

Если signal равно nil - то это эквивалентно false.

13 (2022-08-16 13:44:24 отредактировано swerg)

Re: Передать структуру в функцию.

dark184 пишет:

Да, это есть у меня. Но напрягает синтаксис,
и все без примеров smile

Помню же была нормальная книжка. Попалась:
[url]https://www.lua.org/pil/contents.html[/url]

Здесь всё по-человечески. Про Lua 5.0, но это не важно в данном случае, [url=https://quik2dde.ru/viewtopic.php?id=374]изменения в языке весьма и весьма незначительны[/url].

14

Re: Передать структуру в функцию.

swerg пишет:

Помню же была нормальная книжка. Попалась:

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

    Column_Table =    {                                        -- Создаем список колонок таблицы.
                    {"Инструмент",QTABLE_STRING_TYPE,15,NAME},
                    {"Шаг цены",QTABLE_DOUBLE_TYPE, 12,tostring(PRICE_STEP)},
                    {"Точность",QTABLE_INT_TYPE, 12,tostring (PRICE_SCALE)},
                    {"Open", QTABLE_DOUBLE_TYPE, 10,tostring(Open)},
                    {"High", QTABLE_DOUBLE_TYPE, 10,MakeStringPrice(High)},
                    {"Low", QTABLE_DOUBLE_TYPE, 10,MakeStringPrice(Low)},
                    {"Close", QTABLE_DOUBLE_TYPE, 10,MakeStringPrice(Close)},
                    {"Volume", QTABLE_DOUBLE_TYPE, 15,tostring(Volume)},
                    }

Вот эту структуру передаю в функцию

function Table_init(t)

-- Создаем таблицу и присваиваем имена столбцов из переданного массива t.
    local i = 0
    local Table = AllocTable()
        for i=1,#t,1 do            -- Перебираем массив по строкам от первой до последней. Количество строк массива получаем #t
            AddColumn(Table, i, t[i][1], true, t[i][2], t[i][3])
        end

    CreateWindow(Table)
    SetWindowCaption(Table, "Отладочная таблица")
--    SetWindowPos(Table, 0, 10, 2500, 200)
    InsertRow(Table, -1)

return Table
end

В данном случае все отлично работает. Но если обратить внимание, то четвертым столбцом идут переменные. НО! Здесь получается, что таблица создается, из переменных пишутся в нее значения и само собой больше не обновляются... Второй день ломаю голову как в этот столбец перед инитом вставить не значения переменных, а адрес переменной в памяти по которому и будут забираться значения и обновляться такой или подобной функцией?

-- Заполнение строки таблицы
function Table_row(row)
    local i = 0
    for i=1,#Column_Table,1 do
        SetCell(t_id,row,i,Column_Table[i][4])
    end
end

Отдельную структуру создавать неудобно.

15

Re: Передать структуру в функцию.

dark184 пишет:

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

Или я не понимаю о чем вы, или вы куда-то не туда думаете.
Какой адрес переменной??

Есть функция SetCell, она задает отображаемое значение в ячейке визуальной таблицы.  Всё.

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

16

Re: Передать структуру в функцию.

Поясню немного. Сам я больше привык к си, нет, я не мега спец, просто любитель. Мыслю сишными мозгами... Так вот, например, на си у меня есть переменная temp. Мне имя переменной не нужно по каким либо причинам, а нужен ее адрес по которому я хочу забирать из нее значение. Как это сделать? Очень просто i = #temp, в i окажется не значение, а адрес переменной temp в памяти. Теперь с этим адресом я могу делать что угодно, например прибавить 1, а потом взять значение по этому адресу r = *i. Т.о. даже не зная имени переменной, находящейся в следующей ячейки памяти после temp я могу взять из нее значение. Понятно, что с переменной нет смысла большого с этим заморачиваться, это просто пример. Именно по такому принципу работают абсолютно все массивы в любых языках программирования. Т.е. передается не сам массив, а адрес первого элемента массива.
В моем случае я не могу дошурупить почему инитится жёсткая таблица, с чем проинитил, с тем она и остаётся дальше. У меня только одна мысль, при ините таблицы просто берутся значения переменных один раз и все. Больше не обновляются, хотя переменные меняются, проверено, выводил мессаджами...

17

Re: Передать структуру в функцию.

dark184 пишет:

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

Конечно же нет.
Pyton, C#, Java - очевидно, что там это всё сильно не так.

dark184 пишет:

почему инитится жёсткая таблица

Есть функция SetCell. Она в аргументе принимает текст, который пропишется для отображения в таблицу.
Какие адреса? какие переменные? какие массивы??

SetCell(t_id ,row, i, a)  -- текст из значения переменной a
SetCell(t_id ,row, i, "текст для ячейки")  -- явно заданный в аргументе текст

18 (2022-08-22 15:49:27 отредактировано dark184)

Re: Передать структуру в функцию.

Проблема не в том, как вывести. Именно так я сейчас и делаю. В принципе когда скрипт отлажен, проблем нет. Но! Во время отладки, когда возникает необходимость добавить столбец или приходит понимание что какой то не нужен и его можно удалить, вот тут то и возникают некоторые неудобства. Именно поэтому хотелось изначально, как я выкладывал, создать таблицу, проинитить ее, в теле программы заполнить переменные и одним махом обновлять значения в таблице и только нужную строку. Т.е. при отладке хоть сколько меняешь изначальный массив, а переменные подтягиваются автоматом и только, что нужны на отображение. А так не только за строками, ещё и за столбцами следить приходится.
Т.е. суть вопроса, возможно ли из выше приведенного массива Column_Table каждый четвертый элемент в каждой строке передать не виде значения, а в виде адреса обозначенной переменной по которому я и буду забирать значение функцией SetCell?

19

Re: Передать структуру в функцию.

dark184,
я, признаться, так до конца точно и не смог понять что именно вы хотите.
Вроде так примерно представляю (видимо хочется, чтобы при изменении значения переменной в программе автоматически обновлялась информация в визуальной таблице). Так? или что-то другое?

Возможно что-то такое или подобное можно будет придумать на метатаблицах, например.
Но в любом случае надо будет вызывать какую-то функцию "данные поменялись, обновитесь значения!".

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

20

Re: Передать структуру в функцию.

Далеко не так, автоматически обновлять без функции это почти фантастика... Да и не нужно это.
Вот смотрите, на том же си есть указатели, по сути указатель забирает значение не по имени, по адресу переменной в памяти. В луа как я понял это называется ссылкой, правда такого термина я не нашел... Для переменных в указателях большого смысла нет, но, например, я могу в массив данных загнать указатель вместо имени переменной и программе сказать что в этой ячейке не данные, а указатель, по которому брать значение. Сумбурно, но как то так.
Любой переменной компилятор присваивает адрес, даже локальной. По сути имя и является ее адресом. Но мы не знаем его. Пример, i=10. I здесь имя переменной, пускай компилятор дал ей адрес 12345. Если допустим а = i, то в переменную а я получу значение 10. А вот если так а = *i то в а окажется 12345. Вот этот адрес мне и надо подставить в Column_Table но только в четвертый элемент каждой строки.
Тогда я бы мог забрать значение так Z = #a, теперь в Z лежит 10.
Для чего мне это нужно? Создаю заготовку таблицы, где нужны статичные данные прямо их и пишу. Там где нет, вставляю указатель, он статичен. Но при обновлении строки говорю функции обнови ка мне строку, но имей ввиду, но у тебя в руках не сами данные, а всего лишь указатель(по сути адрес) по которому их забрать...
Таким образом я создаю таблицу с описанием и сразу с нужными мне данными. Каждая строка таблицы содержит все необходимое для каждого столбца. Теперь если я удаляю любую колонку, автоматом вся таблица переписывается вообще без изменения в программе... Пиши себе код дальше...

21

Re: Передать структуру в функцию.

dark184 пишет:

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

Могли бы вы привести пример "кода мечты"? как это должно выглядеть?
Тогда под ответ можно было бы подогнать какое-то приемлемое решение, возможно.
Это просто было бы более однозначно понятно,

Просто пример полного кода (не рабочего, не страшно), который бы вы хотели видеть в итоге.

Возможно на метатаблицах что-то придумать удастся, такое у меня ощущение. А может и проще что-то.

22

Re: Передать структуру в функцию.

В принципе в сообщении от 21 числа и есть именно этот нерабочий пример. Работает все, кроме обновления данных, которые должны браться из 4 элемента каждой строки.

23

Re: Передать структуру в функцию.

Осознал.
Тогда предлагаю сделать так:

    Column_Table = {                                        -- Создаем список колонок таблицы.
                    {"Инструмент",QTABLE_STRING_TYPE,15,function() return NAME end},
                    {"Шаг цены",QTABLE_DOUBLE_TYPE, 12,function() return tostring(PRICE_STEP) end},
                    {"Точность",QTABLE_INT_TYPE, 12,function() return tostring (PRICE_SCALE) end},
                    {"Open", QTABLE_DOUBLE_TYPE, 10,function() return tostring(Open) end},
                    {"High", QTABLE_DOUBLE_TYPE, 10,function() return MakeStringPrice(High) end},
                    {"Low", QTABLE_DOUBLE_TYPE, 10,function() return MakeStringPrice(Low) end},
                    {"Close", QTABLE_DOUBLE_TYPE, 10,function() return MakeStringPrice(Close) end},
                    {"Volume", QTABLE_DOUBLE_TYPE, 15,function() return tostring(Volume) end},
    }

function Table_row(row)
    local i = 0
    for i=1,#Column_Table,1 do
        SetCell(t_id,row,i,Column_Table[i][4]())
    end
end

Т.е. четвертым элементом таблицы мы вписываем не сами значения, а функции, которые возвращают нам нужное значение из переменных, а в  Table_row эти функции вызываем для получения значения (обратите внимание на добавленные 2 скобки в последнем аргументе SetCell).

Проверил, работает.

24 (2022-08-26 12:02:35 отредактировано dark184)

Re: Передать структуру в функцию.

Хм, а чё так можно было??? Доберусь до робота, проверю. Хотя уже даже не сомневаюсь что заработает. Сам бы фиг дошурупил вызвать функцию прямо из массива... Хотя ведь это было более чем очевидное решение. Спасибо.

25 (2022-08-26 13:43:47 отредактировано dark184)

Re: Передать структуру в функцию.

Да, все работает именно так, как и должно, спасибо. Сейчас займусь ещё изменением цвета отдельных ячеек.