-
В условно новых версиях 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);
но он и так самый длинный по синтаксису, профит от него вообще не очень ясен (мне).
Буду признателен за растолковывания или ссылки по теме (помимо справки)
-
-
Ссылку почитал. Там про другое, хотя на память покласть можно этот трюк, спасибо.
У меня вопрос про другое: в моей структуре 2 внутренних поля, при этом при присвоении какого-то значения переменной моего типа требуется указывать инициализирующие значения сразу для обоих полей. И вопрос в том, как синтаксически такую инициализацию в коде написать наиболее понятно / компактно синтаксически.
В С++ это делается просто: TMyType var(2.3, 4);
Либо TMyType var; var := TMyType(2.3, 4);
Собственно вопрос какие максимально короткие синтаксические конструкции позволят проделать аналогичное в Delphi.
-
> Собственно вопрос какие максимально короткие синтаксические > конструкции позволят проделать аналогичное в Delphi.
По ссылке рекомендуют вызывать конструктор. По-другому только константы объявляются или инициализированные глобальные переменные.
> В С++ это делается просто:
Здесь вам не там
-
Class Operator TMyRecord.Implicit(NewValue: Array Of TVarRec): TMyRecord; ...
recVar:=[1, 5];
-
> Redmond (14.02.18 11:50) [4]
Прикольный вариант, спасибо (ну например мы забиваем на оверхед если)
-
Всё зависит от ситуации. Нам же неизвестно что конкретно вы хотите получить. Этот вариант универсален. И ещё не факт что это станет узким местом в коде. А для конкретной ситуации можно и соптимизировать, но надо ж эту ситуацию знать. :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.
|