Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

"Конструирование" записей (record) с использованием методов


KSergey ©   (13.02.18 17:17

В условно новых версиях Delphi появилась возможность добавлять процедуры и функции в пользовательские типы record.
Пусть пользовательский record состоит из 2-х полей и мы хотим их заполнять. Причем обязательно их заполнять, оба.

Вопрос: какие вариации синтаксиса для этого существуют?
Можно ли сделать что-то вроде
  recVar := (1,5);
или
  recVar(1,5);
?

Для определённости обсуждения и примеров пусть будет так:

 TMyRecord = record
   private
     Fpole1: Double;
     Fpole2: Int16;
   public
    constructor Create(p1: Double; p2: Int16 = 8);
 end;

Причем конструктор без параметров определить не даёт(??).

Такое объявление позволяет делать такие инициализации, судя по справке:

var
 d1, d2, d3: TMyRecord;
begin
 d1.Create(7.2, 2);
 d2 := TDepoCount.Create(2);

А какие еще возможны варианты? есть ли варианты какие-то менее многословные? (ожидаемые варианты приведены выше)

Кстати, а какой вообще смысл имеет описание именно конструктора? я что-то не смог найти. Равно как и не сумел найти каких-либо различий между вариантами объявления конструктора и вариантом объявления просто метода, который заполнит поля. Так, если объявить

   public
    procedure Make(p1: Double; p2: Int16 = 8);

то можно будет по прежнему записывать

   d1.Make(7.2, 2);

Будет недоступен вариант

  d2 := TDepoCount.Make(2);

но он и так самый длинный по синтаксису, профит от него вообще не очень ясен (мне).

Буду признателен за растолковывания или ссылки по теме (помимо справки)


Игорь Шевченко ©   (13.02.18 17:33[1]

https://stackoverflow.com/questions/39392920/how-can-delphi-records-be-initialized-automatically

?


KSergey ©   (14.02.18 08:07[2]

Ссылку почитал.
Там про другое, хотя на память покласть можно этот трюк, спасибо.

У меня вопрос про другое: в моей структуре 2 внутренних поля, при этом при присвоении какого-то значения переменной моего типа требуется указывать инициализирующие значения сразу для обоих полей.
И вопрос в том, как синтаксически такую инициализацию в коде написать наиболее понятно / компактно синтаксически.

В С++ это делается просто:
  TMyType var(2.3, 4);

Либо
  TMyType var;
  var := TMyType(2.3, 4);

Собственно вопрос какие максимально короткие синтаксические конструкции позволят проделать аналогичное в Delphi.


Игорь Шевченко ©   (14.02.18 10:28[3]


> Собственно вопрос какие максимально короткие синтаксические
> конструкции позволят проделать аналогичное в Delphi.


По ссылке рекомендуют вызывать конструктор. По-другому только константы объявляются или инициализированные глобальные переменные.


> В С++ это делается просто:


Здесь вам не там


Redmond   (14.02.18 11:50[4]

Class Operator TMyRecord.Implicit(NewValue: Array Of TVarRec): TMyRecord;
...

recVar:=[1, 5];


KSergey ©   (14.02.18 12:09[5]

> Redmond   (14.02.18 11:50) [4]

Прикольный вариант, спасибо (ну например мы забиваем на оверхед если)


Redmond   (14.02.18 16:22[6]

Всё зависит от ситуации. Нам же неизвестно что конкретно вы хотите получить.
Этот вариант универсален. И ещё не факт что это станет узким местом в коде. А для конкретной ситуации можно и соптимизировать, но надо ж эту ситуацию знать. :3
А в С++ те два варианта насколько помнится просто укороченная запись - по факту будет просто вызываться конструктор.

> ... Будет недоступен вариант ...

эм... Потому что для этого надо не procedure, а constructor или хотя бы функцию. Хотя лично мне кажется намного логичнее и удобнее сделать с разными именами - конструктор New и процедуру Init.

Program
     Project1;

{$APPTYPE CONSOLE}

Uses
     System.SysUtils,
     System.Types,
     Winapi.ADOInt;

Type
     TMyRecord = Record
     Private
           FFieldSI: Int16;
           FFieldD: Double;
           Const DEFAULT_VALUE_FieldSI = 8;
     Public
           Constructor Create(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
           Constructor Make(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
           Constructor New(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
           Procedure Init(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
           Class Operator Implicit(NewValue: Array Of TVarRec): TMyRecord; OverLoad;
           Class Operator Implicit(NewValue: TPoint): TMyRecord; OverLoad;
           Class Operator Implicit(NewValue: Winapi.ADOInt.Fields): TMyRecord; OverLoad;
           Procedure Print();
     End;

Constructor TMyRecord.Create(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
Begin
FFieldD:=NewFieldD;
FFieldSI:=NewFieldSI;
End;

Constructor TMyRecord.Make(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
Begin
FFieldD:=NewFieldD;
FFieldSI:=NewFieldSI;
End;

Constructor TMyRecord.New(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
Begin
Init(NewFieldD, NewFieldSI);
End;

Procedure TMyRecord.Init(NewFieldD: Double; NewFieldSI: Int16 = DEFAULT_VALUE_FieldSI);
Begin
FFieldD:=NewFieldD;
FFieldSI:=NewFieldSI;
End;

Class Operator TMyRecord.Implicit(NewValue: Array Of TVarRec): TMyRecord;
Begin
If (Length(NewValue)=0) Then
     Raise Exception.Create('В массиве должен быть как минимум один элемент');
Result.FFieldD:=NewValue[0].VExtended^;
If (Length(NewValue)>1) Then
     Result.FFieldSI:=NewValue[1].VInteger
Else
     Result.FFieldSI:=DEFAULT_VALUE_FieldSI;
End;

Class Operator TMyRecord.Implicit(NewValue: TPoint): TMyRecord;
Begin
Result:=TMyRecord.Create(NewValue.X, NewValue.Y);
End;

Class Operator TMyRecord.Implicit(NewValue: Winapi.ADOInt.Fields): TMyRecord;
Var i: Integer; Item: Field; NewFieldD: Double; NewFieldSI: Int16;
Begin
NewFieldD:=0;
NewFieldSI:=DEFAULT_VALUE_FieldSI;
For i:=0 To (NewValue.Count-1) Do
     Begin
     Item:=NewValue.Item[i];
     If (Item.Name='FieldD') Then
           NewFieldD:=Double(Item.Value);
     If (Item.Name='FieldSI') Then
           NewFieldSI:=Integer(Item.Value);
     End;
Result:=TMyRecord.Create(NewFieldD, NewFieldSI);
End;

Procedure TMyRecord.Print();
Begin
Writeln(Format('{ %f , %d }', [FFieldD, FFieldSI]));
End;

Procedure TestA();
Var RecA, RecB, RecC, RecD, RecE, RecF, RecG, RecH: TMyRecord; SomeTPoint: TPoint;
Begin
(**********************************)
RecA.Create(7.2, 2);
RecA.Print();
(**********************************)
RecB:=TMyRecord.Create(2, 55);
RecB.Print();
(**********************************)
RecC.Make(4.2, 13);
RecC.Print();
(**********************************)
RecD:=TMyRecord.Make(5.3, -19);
RecD.Print();
(**********************************)
RecE:=[6.66, 17];
RecE.Print();
(**********************************)
RecF.Init(33.33, 180);
RecF.Print();
(**********************************)
RecG:=TMyRecord.New(27.1, -9);
RecG.Print();
(**********************************)
Writeln;
SomeTPoint.SetLocation(120, 240);
RecH:=SomeTPoint;
RecH.Print();
(**********************************)
End;

Procedure TestB();
Var RecA, RecB, RecC, RecD, RecE, RecF, RecG: TMyRecord;
Begin
(**********************************)
RecA.Create(7.2);
RecA.Print();
(**********************************)
RecB:=TMyRecord.Create(2);
RecB.Print();
(**********************************)
RecC.Make(4.2);
RecC.Print();
(**********************************)
RecD:=TMyRecord.Make(5.3);
RecD.Print();
(**********************************)
RecE:=[6.66];
RecE.Print();
(**********************************)
RecF.Init(33.33);
RecF.Print();
(**********************************)
RecG:=TMyRecord.New(27.1);
RecG.Print();
(**********************************)
End;

Begin
Try
     Writeln;
     TestA();
     Writeln;
     TestB();
     Writeln;
Except
     On E: Exception Do
           Writeln(E.ClassName, ' :: ', E.Message);
     End;
Readln;
End.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо