Base de Conhecimento

“Unit” Digitação específica em Delphi

Os tipos primitivos têm regras de conversão padrão, muitas linguagens de programação funcionam dessa forma por padrão. Isto é para que você não tenha que digitar tudo e é realmente uma conveniência. Por exemplo, você será capaz de atribuir um Integer a um Extended sem problemas, tanto passando um 42 literal como atribuindo uma variável do tipo Integer.

procedure Hello;
var
  SomeNumber: Extended;
  AnotherNumber: Integer;
begin
  AnotherNumber := 6;
  SomeNumber := 2; // works
  SomeNumber := AnotherNumber; // works
end;

Mesmo que digitem aliasing, os tipos ainda são os tipos que eram e têm regras de conversão automática:

type
  ANewType = Extended;
  AnotherNewType = Integer;

implementation

procedure Hello;
var
  SomeNumber: ANewType;
  AnotherNumber: AnotherNewType;
begin
  AnotherNumber := 6;
  SomeNumber := 2; // works
  SomeNumber := AnotherNumber; // works
end;

Se você realmente quer regras de conversão rigorosas, porque, por exemplo, você quer evitar que os medidores sejam atribuídos a segundos ou vice-versa, você precisará criar novos tipos. E novos tipos são criados usando ou um registro ou uma classe.

Para permitir certas conversões, você pode adicionar essas regras aos tipos utilizando a sobrecarga do operador. (veja https://docwiki.embarcadero.com/RADStudio/Sydney/en/Operator_Overloading_(Delphi))

No FPC a sintaxe é diferente, mas você pode fazer o mesmo https://www.freepascal.org/docs-html/ref/refse104.html#x224-24800015.3

Você pode até mesmo fazer regras de conversão para metros * segundos criando um tipo de metro por segundo.

Aqui está um exemplo de como funciona em Delphi:

 

type
  metersPerSecond = record
  private
    m: Extended;
    s: Extended;
 
    value: extended;
 
    mset: Boolean;
    sset: Boolean;
 
    function Units: string;
  public
    function ToString: string;
  end;
 
  meters = record
  private
    value: Extended;
 
    function Units: string;
  public
    class operator Implicit(Value: Extended): meters;
    class operator Explicit(Value: meters): metersPerSecond;
    class operator Multiply(ms: metersPerSecond; m: meters): metersPerSecond;
 
    function ToString: string;
  end;
 
  seconds = record
  private
    value: Extended;
 
    function Units: string;
  public
    class operator Implicit(Value: Extended): seconds;
    class operator Explicit(Value: seconds): metersPerSecond;
    class operator Multiply(ms: metersPerSecond; s: seconds): metersPerSecond;
 
    function ToString: string;
  end;
 
implementation
 
uses
  SysUtils;
 
class operator meters.Implicit(Value: Extended): meters;
begin
  Result.value := Value;
end;
 
class operator seconds.Implicit(Value: Extended): seconds;
begin
  Result.value := Value;
end;
 
class operator meters.Explicit(Value: meters): metersPerSecond;
begin
  Result.m := Value.value;
  Result.mset := True;
  if Result.sset then
    Result.value := Result.s * Result.m; 
end;
 
class operator seconds.Explicit(Value: seconds): metersPerSecond;
begin
  Result.s := Value.value;
  Result.sset := True;
  if Result.mset then
    Result.value := Result.s * Result.m; 
end;
 
class operator seconds.Multiply(ms: metersPerSecond; s: seconds): metersPerSecond;
begin
  Result := ms;
  Result.s := s.value;
  Result.sset := True;
  if Result.mset then
    Result.value := Result.s * Result.m; 
end;
 
class operator meters.Multiply(ms: metersPerSecond; m: meters): metersPerSecond;
begin
  Result := ms;
  Result.m := m.value;
  Result.mset := True;
  if Result.sset then
    Result.value := Result.s * Result.m; 
end;
 
function metersPerSecond.Units: string;
begin
  Result := 'm/s';
end;
 
function metersPerSecond.ToString: string;
begin
  Assert(mset and sset);
 
  Result := Format('%f%s', [value, Units])
end;
 
function meters.Units: string;
begin
  Result := 'm';
end;
 
function meters.ToString: string;
begin
  Result := Format('%f%s', [value, Units]);
end;
 
function seconds.Units: string;
begin
  Result := 's';
end;
 
function seconds.ToString: string;
begin
  Result := Format('%f%s', [value, Units]);
end;
 
var
  time: seconds;
  distance: meters;
  speed: metersPerSecond;
  different_speed: metersPerSecond;
initialization
  time := 10.0;
  distance := 3;
 
  // distance := meters; // does not work, because seconds are not meters!
 
  speed := metersPerSecond(time) * distance;
 
  // or the other way around
  speed := metersPerSecond(distance) * time;
 
  WriteLn('speed -> ' + time.ToString + ' * ' + distance.ToString + ' = ' + Speed.ToString);
 
  // different_speed := distance; // this doesn't work without explicit conversion
 
  WriteLn('different_speed -> ' + different_speed.ToString);
end.

Written by Patrick Quist
Desenvolvedor Delphi

Contato

Deixe-nos ajudá-lo a realizar seus sonhos.