Recent

Author Topic: Неправильно исполняется код  (Read 1090 times)

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #15 on: August 14, 2019, 04:59:43 pm »
Один всё таки озвучу. Например буквально на днях в проекте создавал класс который включал в себя массив записей. В записях планировал создать два поля типа boolean, последовательность действий была такая - сначала описал только одно поле с данным типом, проверил - всё работало, как только добавил второе поле с таким же типом, программа работать перестала. Убирал второе поле - работало, добавлял - переставало.  Сам код не сохранился...
я бы предложил реализовать проект ещё раз, и проверить воспроизведётся ошибка или нет.
Без кода, разговор получится на пустом месте.

но я уже вижу тревожные звоночки в виде:
Code: Pascal  [Select]
  1.      procedure StatDataToStringGrid(var StringGrid:TstringGrid);
  2.      procedure StringGridAutoSize(Var StringGrid:TstringGrid);
  3.      procedure StatDataToTabel(var tab:TTabel);
а именно - тревожит наличие "var". Причём, я не думаю, что ошибка была в исползовании "var". Просто само его использование в данным случае излишне. "var" для класса имеет несколько иное значение, чем "var" для record-а.


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

По поводу var - хотелось бы знать отличие. В данном случае поставил var, чтобы процедура работала непосредственно с данными классами не создавая копию. Без них код не работал - данные из процедур не передавались далее. Кстати, процедура procedure StatDataToTabel(var tab:TTabel); у меня так и не заработала как надо. Почему опять таки я не понял.

Код её следующий:
procedure TStatistic.StatDataToTabel(var tab:TTabel); //не работает
var i:integer;
    tempTab:TTabel;
    new:TRow;
 begin
   tempTab:=TTabel.Create;
   new:=TRow.Create;
   SetLength(new.Cells,3);
   SetLength(tempTab.Rows,length(SData)+1);
   new.Cells[0]:=systoutf8('Дата');
   new.Cells[1]:=systoutf8('Приход');
   new.Cells[2]:=systoutf8('Уход');
   tempTab.AddRow(new);
   tempTab.Rows[0]:=new;
  // showmessage(tempTab.Rows[0].RowToUTF8String);
   for i:=1 to length(SData)+1 do
    begin
     //showmessage(tempTab.Rows[0].RowToUTF8String);
     new.Cells[0]:=DateToStr(SData.date,FormatSettings);
     new.Cells[1]:=IntToStr(SData.input);
     new.Cells[2]:=IntToStr(SData.output);
     tempTab.Rows:=new;   //tempTab.AddRow(new);
    // showmessage(tempRow.RowToUTF8String);
    end;
   tab:=temptab;
 end;

Коротко о том, что происходит - класс TTabel - это класс таблиц мною созданный. В TTabel имеется массив TRow, который является строками в таблицах, в TRow имеются массивы Cells. Т.е. для создания таблицы 3x3 мы задаем количество ячеек Cells в TRow равное 3-м и добавляем три таких Row в TTabel. Сам класс TTabel уже использовал в проекте и всё работало достаточно долго (проект начал в 2017).
Эта процедура должна записать данные из SData (Массив записей с полями текущей даты, прихода и ухода. Даты в массиве идут последовательно по дням например 01.01.2019, 02.01.2019 и т.д.) в таблицу Tab. По результату получается, что вся таблица Tab заполнена данными только за одну дату - последнюю. В классе TTabel есть процедура Add для добавления строк, изначально использовал её, по вышеозвученному результату предположил, что дело в ней (хотя в других случаях она всегда работала) и реализовал добавление строк к таблицу так как написано в коде выше. Но результат оказался идентичным. В комментариях стоят showmessage - таким образом следил за тем, что происхоидит - одно могу сказать точно - SData заполнен нужными данными и вопрос тут в том, как они записываются в TTabel.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2289
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #16 on: August 14, 2019, 05:22:41 pm »
По поводу var - хотелось бы знать отличие. В данном случае поставил var, чтобы процедура работала непосредственно с данными классами не создавая копию. Без них код не работал - данные из процедур не передавались далее. Кстати, процедура procedure StatDataToTabel(var tab:TTabel); у меня так и не заработала как надо. Почему опять таки я не понял.
Тип класс-а в Object Pascal-е (и FPC и Delphi) всегда ссылочный.
"var" для переменной класса, означает, что ссылка может быть изменена.
При наличии var, или без него, копии данных создаваться не будет (опять же потому что передаётся ссылка на объект класса)

В большинстве случаев нужды в var нет. Кроме тех случаев, когда нужно создать объект класса (или, реже, поменять ссылку на объект класса).

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

После чего один ряд перезаписывается N раз (где N соответствует количеству дат - 1); И в единственно добавленный ряд попадает последняя запись из SDate
« Last Edit: August 14, 2019, 05:27:38 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #17 on: August 14, 2019, 05:41:30 pm »

Тип класс-а в Object Pascal-е (и FPC и Delphi) всегда ссылочный.
"var" для переменной класса, означает, что ссылка может быть изменена.
При наличии var, или без него, копии данных создаваться не будет (опять же потому что передаётся ссылка на объект класса)

В большинстве случаев нужды в var нет. Кроме тех случаев, когда нужно создать объект класса (или, реже, поменять ссылку на объект класса).

Тогда непонятно почему данные не передавались без var...

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

После чего один ряд перезаписывается N раз (где N соответствует количеству дат - 1); И в единственно добавленный ряд попадает последняя запись из SDate

Странно, почему-то код как-то криво скопировался. Мы присваиваем в цикле и присваивается не одни и те же данные, а разные. Берутся из массива SData по индексу i. Индекс меняется, соответсвенно и данные должны записываться разные.

procedure TStatistic.StatDataToTabel(var tab:TTabel); //не работает
var i:integer;
    tempTab:TTabel;
    new:TRow;
 begin
   tempTab:=TTabel.Create;
   new:=TRow.Create;
   SetLength(new.Cells,3);
   SetLength(tempTab.Rows,length(SData)+1);
   new.Cells[0]:=systoutf8('Дата');
   new.Cells[1]:=systoutf8('Приход');
   new.Cells[2]:=systoutf8('Уход');
   tempTab.AddRow(new);
   tempTab.Rows[0]:=new;
  // showmessage(tempTab.Rows[0].RowToUTF8String);
   for i:=1 to length(SData)+1 do
    begin
     //showmessage(tempTab.Rows[0].RowToUTF8String);
     new.Cells[0]:=DateToStr(SData.date,FormatSettings);
     new.Cells[1]:=IntToStr(SData.input);
     new.Cells[2]:=IntToStr(SData.output);
     tempTab.Rows:=new;   //tempTab.AddRow(new);
    // showmessage(tempRow.RowToUTF8String);
    end;
   tab:=temptab;
 end;

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #18 on: August 14, 2019, 05:42:50 pm »
Не хочет код правильно постить. В общем в цикле после SData идут квадратные скобки и индекс i внутри  них. SData - это массив записей.

Похоже, что здесь такой набор символов воспринимается как тег и весь последующий текст становится курсивом
« Last Edit: August 14, 2019, 05:44:43 pm by devisa_san »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2289
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #19 on: August 14, 2019, 05:44:52 pm »
правильно постить код, можно при помощи тэга:
Code: [Select]
[code=pascal]
  writeln('hello world');
[ /code]
(пробел в закрывающем тэге между "[" и "/code]" нужно убрать. здесь он для примера)

результат:
Code: Pascal  [Select]
  1.   writeln('hello world');

https://wiki.freepascal.org/Forum#Use_code_tags

В общем в цикле после SData идут квадратные скобки и индекс i внутри  них. SData - это массив записей.
это всё хорошо, но в цикле, в котором ты проходишь SData, ты не создаёшь новых рядов для TTabel.
У тебя даже закоментирован код tempTab.AddRow(new);
И он правильный, но только при условии, что "new" будет точно так же оздаваться внутри цикла, а не до него.
« Last Edit: August 14, 2019, 05:56:07 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #20 on: August 14, 2019, 06:12:13 pm »
правильно постить код, можно при помощи тэга:
Code: [Select]
[code=pascal]
  writeln('hello world');
[ /code]
(пробел в закрывающем тэге между "[" и "/code]" нужно убрать. здесь он для примера)

результат:
Code: Pascal  [Select]
  1.   writeln('hello world');

https://wiki.freepascal.org/Forum#Use_code_tags

В общем в цикле после SData идут квадратные скобки и индекс i внутри  них. SData - это массив записей.
это всё хорошо, но в цикле, в котором ты проходишь SData, ты не создаёшь новых рядов для TTabel.
У тебя даже закоментирован код tempTab.AddRow(new);
И он правильный, но только при условии, что "new" будет точно так же оздаваться внутри цикла, а не до него.

Мой косяк. Не тот код всё таки запостил. Там закомментированна строчка - это то, что должно было выполняться и оно не работало. А закомментировал я её просто потому что пробовал разные варианты и в текущем смотрел, что вообще запишется. Т.е. должно работать, если new создавать каждый новый цикл? Но почему? Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляр и потому результат и получается таким, что таблица состоит только из того, что было в последней строке?

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2289
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #21 on: August 14, 2019, 07:01:35 pm »
Т.е. должно работать, если new создавать каждый новый цикл?
да
Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляр и потому результат и получается таким, что таблица состоит только из того, что было в последней строке?
нет. TTabel у тебя один.
у тебя на каждую итерацию нужно создавать новый TRow.
сколько рядов, столько раз TRow нужно создавать.
Code: Pascal  [Select]
  1. procedure TStatistic.StatDataToTabel(var tab:TTabel); //не работает
  2. var i:integer;
  3.     tempTab:TTabel;
  4.     new:TRow;
  5. begin
  6.   tempTab:=TTabel.Create;
  7.   new:=TRow.Create;
  8.   SetLength(new.Cells,3);
  9.   SetLength(tempTab.Rows,length(SData)+1);
  10.   new.Cells[0]:=systoutf8('Дата');
  11.   new.Cells[1]:=systoutf8('Приход');
  12.   new.Cells[2]:=systoutf8('Уход');
  13.   tempTab.AddRow(new);
  14.   tempTab.Rows[0]:=new;
  15.  
  16.   for i:=1 to length(SData)+1 do begin
  17.     new:=TRow.Create;
  18.     SetLength(new.Cells,3);
  19.     new.Cells[0]:=DateToStr(SData[i-1].date,FormatSettings);
  20.     new.Cells[1]:=IntToStr(SData[i-1].input);
  21.     new.Cells[2]:=IntToStr(SData[i-1].output);
  22.     tempTab.Rows[i]:=new;  
  23.   end;
  24.   tab:=temptab;
  25. end;
  26.  
« Last Edit: August 14, 2019, 07:05:44 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #22 on: August 14, 2019, 08:38:38 pm »
нет. TTabel у тебя один.
у тебя на каждую итерацию нужно создавать новый TRow.
сколько рядов, столько раз TRow нужно создавать.

Почему нет? Фишка в том, что в результате получается таблица в которой количество TRow правильное, но эти TRow одинаковые. Что тогда в данном варианте происходит? Получается на каждой итерации я присваиваю значение одному и тому же экземпляру класса, а в TTabel у меня храняться только ссылки на него. И тогда мне становится понятно, почему вся таблица была заполнена теми значениями, что в SData были последние. И тогда действительно всё должно заработать, если создавать в цикле каждый раз новый TRow.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2289
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #23 on: August 14, 2019, 08:46:22 pm »
Почему нет?
потому что ранее ты писал про "TTabel":
Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляр
из контекста понятно, что ты говоришь про TRow.
Но т.к. ты создаёшь и TTabel и TRow тебе следует быть внимательнее.
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

devisa_san

  • New Member
  • *
  • Posts: 12
Re: Неправильно исполняется код
« Reply #24 on: August 14, 2019, 08:55:18 pm »
Почему нет?
потому что ранее ты писал про "TTabel":
Потому что мы каждый раз при добавлении передаём ссылку на экземпляр класса в TTabel, а если этого не делать, то все записи в TTabel будут ссылками на один и тот же экземпляр
из контекста понятно, что ты говоришь про TRow.
Но т.к. ты создаёшь и TTabel и TRow тебе следует быть внимательнее.

Прошу прощения, действительно по невнимательности написал TTabel имея ввиду TRow. В остальном размышления верны?

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2289
    • havefunsoft.com
Re: Неправильно исполняется код
« Reply #25 on: August 14, 2019, 09:13:08 pm »
В остальном размышления верны?
да
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz