Конференция "Начинающим" » "Конструирование" записей (record) с использованием методов
 
  • KSergey © (13.02.18 17:17) [0]
    В условно новых версиях 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]
  • 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.
 
Конференция "Начинающим" » "Конструирование" записей (record) с использованием методов
Есть новые Нет новых   [118573   +11][b:0][p:0]