【问题标题】:Delphi: how to express an empty TDateTime?Delphi:如何表示一个空的TDateTime?
【发布时间】:2015-11-25 22:13:30
【问题描述】:

是否可以将空(零)TDateTime 值表示为常数?我尝试了TDateTime(0)TDateTime(0.0) 和其他东西,但编译器(Delphi 7)并没有留下深刻的印象。

目前我正在使用一个初始化的全局变量:

const
   TDateTime_0: TDateTime = 0.0;

这类作品。但是,我只是继承了一大堆很好的 Delphi 7 代码,而且我已经很久没有使用过 Turbo Pascal 了……这意味着我真的需要重新学习我的 Delphi fu,这让我很想知道。

相比之下,编译器对Integer(0) 之类的东西非常满意。将其分配给变体会产生 ftInteger 类型的值 0,而分配纯文字 0 会产生 ftSmallInt 类型的变体。

澄清:目标是将特定类型的“空”值传递给接受变体的函数(其中包括编译器管理的变体数组,称为“const 数组”以及诸如 TParameter.Value 之类的设置器)。

Ken White 的澄清:这里的问题本质上是类型推导和重载解析;上面提到的“采用变体的函数”只是一个特例。文字00.0 可以隐式转换为TDateTime,这就是为什么它们可以分配给那种类型的容器(变量、记录字段)并且它们可以用来初始化这样的容器(即函数参数),而无需再多说一句。但是,当编译器需要进行类型推导时,情况就会发生变化:

procedure foo (value: Double); overload; 
procedure foo (value: TDateTime); overload;

在这两种情况下,基础类型都是 Double,这意味着编译器需要显式输入参数(即,使用纯文字的调用会因为不明确而被拒绝)。对于基于序数的类型,显式类型没有问题,但 Double 类型是有问题的,并且需要在使用之前将值填充到类型化的容器中。可编译示例(需要比 Delphi 7 更新一点的 Delphi):

type
   TSomeId = type Integer;

procedure foo (value: Integer  ); overload;  begin  WriteLn('Integer   ', value);  end;
procedure foo (value: TSomeId  ); overload;  begin  WriteLn('TSomeId   ', value);  end;
procedure foo (value: Double   ); overload;  begin  WriteLn('Double    ', value);  end;
procedure foo (value: TDateTime); overload;  begin  WriteLn('TDateTime ', value);  end;

procedure test_TYPE_Double;
var
   d: Double;
   t: TDateTime;
begin
   foo(Integer(0));
   foo(TSomeId(0));
   d := 0;  foo(d);
   t := 0;  foo(t);
end;

我的问题是/只是是否可以像示例中的IntegerTSomeId 一样形成TDateTime 类型(或基于Double 的其他类型)的表达式上面,没有为此目的分配和初始化类型化的内存位置。但是,Yuriy 的回答表明这仅适用于序数类型。

【问题讨论】:

  • 我问的是一个编译时常量表达式,它被标记为 TDateTime 类型,就像 Integer(0) 的类型是 Integer 而不是 SmallInt 作为普通 (' untyped') 文字 0 将是。我故意避免使用“类型常量”这个术语,因为 Borland/Embarcadero 的知识将它用于只读初始化变量,这不是一回事。表达式的确切类型 - 常量或其他 - 在编译器需要进行类型推导的上下文中是相关的;分配给(或初始化)变体是一种情况,重载决议是另一种情况。
  • @KenWhite 基本上他抱怨 Delphi 违反了自己的 type x = TYPE y 构造,该构造应该是一个完全不相关的类型,没有隐式类型转换。有点类似于我的抱怨stackoverflow.com/questions/11029353
  • @DarthGizka 我相信你可以尝试在最近的 Delphi 中使用Advanced Records + Operators Overloadingimplicit type-cast 来实现。如果您的记录将有隐式的内联类型转换到/从 TDateTime 但不是到/从 double 比可能 - 也许 - 它可以工作。然而,对于这些概念来说,Delphi 7 太旧了。不知道关于 FPC/Lazarus/CodeTyphon
  • 您的最后一次编辑使问题更加清晰。谢谢你这样做。 :-)

标签: delphi-7 delphi


【解决方案1】:

编译器可以将序数类型转换为其他序数类型,但拒绝将浮点类型相互转换,即使它们完全相同:

TMyOwnDouble = type double;
...
var a,b: TMyOwnDouble;
...
a:=MyOwnDouble(0.0); //invalid typecast
b:=0.0;  //no problem

你到底想要什么?如果需要这个 TDateTime 常量只是为了将它传递给需要 TDateTime 的函数,那么你可以只传递 0.0 并且它会起作用:

caption:=DateTimeToStr(0.0); //it shows 30.12.1899

有两个功能很方便:

function FloatToDateTime(const Value: Extended): TDateTime; //sysUtils unit

它检查 Value 的边界,如果没问题,则进行单一分配。

function VarFromDateTime(DateTime: TDateTime): Variant;  //Variants unit

这个显式地创建了 DateTime 变体。 我在这样的代码中尝试了它们,它们的工作方式相同:

var V: Variant;
...
V:=VarFromDateTime(0.0);
//V:=FloatToDateTime(0.0);  //works as well
Caption:=V;  //shows 0:00:00

这样的代码可能比使用 TDateTime_0 常量更容易理解,但体积更大。

【讨论】:

  • 这适用于参数类型为TDateTime 的函数,但不适用于带有变体的函数。我已经为我的问题添加了相应的说明。无论如何+1 :-)
  • 谢谢尤里。您提到的两个函数非常方便,因为它们非常明确地说明了调用站点的意图(à la 'self-documenting source code')。
  • 浮点转换无效,因为来自 C 或 C++ 的太多人期望 Double(MyInteger) 执行从整数到双精度的转换,而不是真正发生的情况,重新解释位。在此之前,演员表曾经是有效的。我认为这在非​​常早期的 Delphi 版本中甚至在 Turbo/Borland Pascal 中都已更改。
【解决方案2】:

将日期设置为“gg” 这会将日期设置为空白。

【讨论】:

  • 我认为您不熟悉用于此问题的标签或语言。在发布答案之前,您应该确保自己是。如果你没有清楚地理解问题,最好不要尝试回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
  • 2011-06-28
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 2018-08-22
  • 1970-01-01
相关资源
最近更新 更多