14

如何在 Delphi中最好地实现三值逻辑?

我在想

type
  TExtBoolean = (ebTrue, ebFalse, ebUnknown);

function ExtOr(A: TExtBoolean; B: TExtBoolean): TExtBoolean;
begin
  if (A = ebTrue) or (B = ebTrue) then
    Result := ebTrue
  else if (A = ebFalse) and (B = ebFalse) then
    Result := ebFalse
  else
    Result := ebUnknown;
end;

等等。

但这似乎不是很优雅。是否存在更好的方法?

编辑:优雅我的意思是易于使用。实现越优雅越好。CPU 效率对我来说并不重要。

4

2 回答 2

15

您可以通过运算符重载来实现增强的记录。它看起来像这样:

type
  TTriBool = record
  public
    type
      TTriBoolEnum = (tbFalse, tbTrue, tbUnknown);
  public
    Value: TTriBoolEnum;
  public
    class operator Implicit(const Value: Boolean): TTriBool;
    class operator Implicit(const Value: TTriBoolEnum): TTriBool;
    class operator Implicit(const Value: TTriBool): TTriBoolEnum;
    class operator Equal(const lhs, rhs: TTriBool): Boolean;
    class operator LogicalOr(const lhs, rhs: TTriBool): TTriBool;
    function ToString: string;
  end;

class operator TTriBool.Implicit(const Value: Boolean): TTriBool;
begin
  if Value then
    Result.Value := tbTrue
  else
    Result.Value := tbFalse;
end;

class operator TTriBool.Implicit(const Value: TTriBoolEnum): TTriBool;
begin
  Result.Value := Value;
end;

class operator TTriBool.Implicit(const Value: TTriBool): TTriBoolEnum;
begin
  Result := Value.Value;
end;

class operator TTriBool.Equal(const lhs, rhs: TTriBool): Boolean;
begin
  Result := lhs.Value=rhs.Value;
end;

class operator TTriBool.LogicalOr(const lhs, rhs: TTriBool): TTriBool;
begin
  if (lhs.Value=tbTrue) or (rhs.Value=tbTrue) then
    Result := tbTrue
  else if (lhs.Value=tbFalse) and (rhs.Value=tbFalse) then
    Result := tbFalse
  else
    Result := tbUnknown;
end;

function TTriBool.ToString: string;
begin
  case Value of
  tbFalse:
    Result := 'False';
  tbTrue:
    Result := 'True';
  tbUnknown:
    Result := 'Unknown';
  end;
end;

一些示例用法:

var
  x: Double;
  tb1, tb2: TTriBool;

tb1 := True;
tb2 := x>3.0;
Writeln((tb1 or tb2).ToString);

tb1 := False;
tb2.Value := tbUnknown;
Writeln((tb1 or tb2).ToString);

输出:

真的
未知
于 2013-10-23T08:48:44.097 回答
5

作为。elegancre 在这里是什么意思?实施的优雅还是使用的优雅或CPI效率或可维护性?优雅是一个非常模糊的词...

我认为使其更易于使用的明显方法 是将类型转换为可用于ExtBoolean1 or (ExtBoolean2 and True).

然而,所需的功能可能在 Delphi 2006 之前或不足(本身相当错误的版本),所以带上你DUnit并做很多测试..

要列出要使用的功能及其描述:

  1. 增强记录:什么时候应该在 Delphi 中使用增强记录类型而不是类?http://delphi.about.com/od/adptips2006/qt/newdelphirecord.htm手册
  2. 操作重载,包括隐式类型转换:将“增强记录”分配给普通“数据类型”变量时,我应该重载什么运算符?Delphi和手册中的运算符重载
  3. 函数内联:delphi手册中 inline 关键字的用途

概述其中一些想法:

type
  TExtBoolean = record
     Value: (ebUnknown, ebTrue, ebFalse);

     function IsNull: boolean; inline;
     function Defined: boolean; inline;

     class operator Implicit ( from: boolean ): TExtBoolean; inline;
     class operator Implicit ( from: TExtBoolean ): boolean; 
     class operator LogicalAnd( Value1, Value2: TExtBoolean ):   TExtBoolean; 
     class operator LogicalAnd( Value1: TExtBoolean; Value2: boolean):  TExtBoolean; inline;
     class operator LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
....
  end;

const Unknown: TExtBoolean = (Value: ebUnknown); 

...
var v1: TExtBoolean;
    v1 := False; 
    v1 := True;
    v1 := Unknown;
...

class operator TExtBoolean.Implicit ( from: boolean ): TExtBoolean; 
begin
  if from
     then Result.Value := ebTrue
     else Result.Value := ebFalse
end;

class operator TExtBoolean.Implicit ( from: TExtBoolean ): Boolean; 
begin
  case from.Value of
    ebTrue: Result := True;
    ebFalse: Result := False;  
    else raise EConvertError.Create('....');
end;


function TExtBoolean.Defined: boolean; 
begin
  Result := (Self.Value = ebTrue) or (Self.Value = ebFalse);
end;

// this implementation detects values other than ebTrue/ebFalse/ebUnkonwn
// that might appear in reality due to non-initialized memory garbage 
// since hardware type of Value is byte and may be equal to 3, 4, ...255
function TExtBoolean.IsNull: boolean; 
begin
  Result := not Self.Defined
end;

class operator TExtBoolean.And( Value1, Value2: TExtBoolean ): TExtBoolean; 
begin
  if Value1.IsNull or Value2.IsNull
     then Result.Value := eb.Undefined
     else Result := boolean(Value1) and boolean(Value2);
// Or, sacrificing readability and safety for the sake of speed
// and removing duplicate IsNull checks
//   else Result := (Value1.Value = ebTrue) and (Value2.Value = ebTrue);
end;

class operator TExtBoolean.LogicalAnd( Value1, TExtBoolean; Value2: boolean):  TExtBoolean;
begin
  Result := Value2 and Value1;
end;

class operator TExtBoolean.LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
begin
  if Value2.IsNull
     then Result := Value2
     else Result := Value1 and (Value2.Value = ebTrue);
// or if to accept a duplicate redundant check for readability sake
//   and to avert potential later erros (refactoring, you may accidentally remove the check above)
//    else Result := Value1 and boolean (Value2);
end;

ETC

PS。上面未指定的检查是故意悲观的,倾向于在坏的方面犯错。它是针对未初始化变量和未来可能发生的变化的防御,添加的状态多于三个。虽然 thise 似乎保护过度,但至少 Delphi XE2 同意 mee:请参阅类似情况下的警告:

program Project20;  {$APPTYPE CONSOLE}
uses System.SysUtils;

type enum = (e1, e2, e3);
var e: enum;

function name( e: enum ): char;
begin
  case e of
    e1: Result := 'A';
    e2: Result := 'B';
    e3: Result := 'C';
  end;
end;

// [DCC Warning] Project20.dpr: W1035 Return value of function 'name' might be undefined

begin
  for e := e1 to e3
      do Writeln(name(e));
  ReadLn;
end.
于 2013-10-23T08:36:43.313 回答