Motto

В тихом саду здравомыслия
Пусть на вас постоянно падают
кокосовые орехи пробужденности.
Чогьям Трунгпа РИНПОЧЕ


пятница, 24 июля 2009 г.

Обобщенное программирование(generics) в Delphi 2009 для Win32. Часть 4. Создание обобщенной записи.

В пособии также рассматриваются анонимные методы и процедурные ссылки.



Словарь терминов
  • generics - дженерики, генерики, параметризованные классы, шаблоны, обобщения;
  • Типы данных: string – строка, record – запись;
  • implicit conversion - неявное приведение (типа);

IV. Создание обобщённой записи

Давайте изучим кое-что ещё и попробуем разработать простенькую, но полезную запись TNullable<T>. Идея состоит в том, чтобы создать запись, которая сможет иметь значения типа T, либо nil. Вы наверное уже задумывались о необходимости такого типа, например для представления значений Null из баз данных.

Эта запись будет содержать два поля: FValue типа T, и булевое поле FIsNil. Для чтения полей, созданы два свойства. Мы будем использовать лишь операторы неявного приведения (типов), чтобы построить значения этого типа.

unit Generics.Nullable;
interface
type
  TNullable<T> = record
  private
 FValue: T;
 FIsNil: Boolean;
  public
 class operator Implicit(const Value: T): TNullable<T>;
 class operator Implicit(Value: Pointer): TNullable<T>;
 class operator Implicit(const Value: TNullable<T>): T;
 property IsNil: Boolean read FIsNil;
 property Value: T read FValue;
  end;
image

За дополнительной информацией о перегрузке операторов я советую обратиться к франкоязычной статье La surcharge d'opérateurs sous Delphi 2006 Win32, которую написал Laurent Dardenne (примечание переводчика: я не нашёл аналогичного материала на русском языке).

Таким образом, это неизменяемый тип (объект, чьё состояние не может быть изменено после создания).

Реализация трех операторов преобразования достаточно проста. Второй (с параметром Pointer) нужен для того, чтобы можно было делать присвоение : = nil.

uses
  SysUtils;
   
resourcestring
  sCantConvertNil = 'Cannot convert to nil';
  sOnlyValidValueIsNil = 'The only valid value is nil';
   
class operator TNullable<T>.Implicit(const Value: T): TNullable<T>;
begin
  Result.FValue := Value;
  Result.FIsNil := False;
end;
   
class operator TNullable<T>.Implicit(Value: Pointer): TNullable<T>;
begin
  Assert(Value = nil, sOnlyValidValueIsNil);
  Result.FIsNil := True;
end;
   
class operator TNullable<T>.Implicit(const Value: TNullable<T>): T;
begin
  if Value.IsNil then
    raise EConvertError.Create(sCantConvertNil);

  Result := Value.FValue;
end;

Использовать эту запись можно так:

  var
 Value: Integer;
 NullValue: TNullable<Integer>;
  begin
 NullValue := 5;
 WriteLn(Integer(NullValue));
 NullValue := nil;
 if NullValue.IsNil then
   WriteLn('nil')
 else
   WriteLn(NullValue.Value);
   
 NullValue := 10;
 Value := NullValue;
 WriteLn(Value);
  end;

Результат выполнения будет таким:

5

nil

10

Всё понятно? Это просто чудесно, учитывая, что я не дал ни единого пояснения. Это лишний раз доказывает, что дженерики это также просто как пирог :-). (примечание переводочника: не знаю почему автор считает что пирог – это просто. Я как-то пробовал испечь один, и скажу честно - программирование намного проще)

Полный исходный код Generics.Nullable доступен для скачивания в конце учебника.



Публикации по теме

3 человек заметили этот пост:

Alex Neznanov комментирует...

easy as pie - идиоматическое выражение, обозначающее "очень простое действие" (этимология - отличие cake от pie, то есть сравнительная простота). Адекватный перевод - "как два пальца ... " (нет, грубо), лучше "как два байта переслать". Но есть много других хороших русских выражений.

Aleksey Timohin комментирует...

Спасибо за замечание Alex (особенно за этимологическую справку)!

Aleksey Timohin комментирует...

п.с. я всё-таки оставлю свою дословную версию (к ней довольно неплохо приклеилась моя несмешная шутка), да и для использования любой из этиъ фраз придётся заменять простоту дженериков на простоту действий над ними, а это как-то не комильфо.

Отправить комментарий

Читатели