我即将编写一个解析器,将文本文件逐行读取到不同类型的结构中,并将这些结构提供给回调(观察者或访问者 - 尚不确定)。
文本文件包含 MT-940 数据 - SWIFT 银行对帐单。
这些行由一个指定类型的标记和一些字段(例如日期)组成,这些字段应该被解析为我的消息的类型安全成员。其中一些字段是可选的 - 所以我的问题是:如何在 D 中表示可选值。
C++ 提供了我的东西,比如你可能知道的 boost::optional。
我目前通过自己实现一个 Optional(T) 来解决这个问题(请参阅本文末尾的代码)。它是一个结构,其中包含一个可能为 null 的 ValueHolder 实例——这标志着没有赋值的情况。如有必要,我重写了 copy-c'tor 和赋值运算符以创建 ValueHolder 的深层副本。
这是要走的路吗?还有其他更简单的选项我看不到吗?
这是我的代码 - 功能不一定完整:
struct Optional(T)
{
class ValueHolder
{
T value;
this(T v)
{
value = v;
}
}
private ValueHolder m_value;
/* Construction without value / with value */
this(T value)
{
m_value = new ValueHolder(value);
}
/* Copy construction / assignment */
ref Optional!(T) opAssign(Optional!(T) rhs)
out
{
if (rhs.m_value !is null)
{
assert(rhs.m_value != m_value);
}
else
{
assert(m_value is null);
}
}
body
{
m_value = null;
if (rhs)
{
m_value = new ValueHolder(rhs.m_value.value);
}
return this;
}
ref Optional!(T) opAssign(T value)
out
{
assert(hasValue());
assert(m_value.value == value);
}
body
{
if (m_value is null)
{
m_value = new ValueHolder(value);
}
else
{
m_value.value = value;
}
return this;
}
this(Optional!(T) rhs)
out
{
if (rhs.m_value !is null)
{
assert(rhs.m_value != m_value);
}
else
{
assert(m_value is null);
}
}
body
{
if (rhs.m_value !is null)
{
m_value = new ValueHolder(rhs.m_value.value);
}
}
/* Implicit cast to bool */
bool hasValue() const
{
return m_value !is null;
}
X opCast(X: bool)()
{
return hasValue();
}
/* Value access */
T opUnary(string s)() const
in
{
assert(s == "*");
assert(m_value !is null);
}
body
{
return m_value.value;
}
}
/* Default Constructed Struct does not have a value assigned */
unittest
{
Optional!(int) x;
assert(x.hasValue() == false);
assert(!x);
}
/* Construction with value */
unittest
{
Optional!(int) x = 3;
assert(x);
assert(x.hasValue());
}
/* Assignment operator does copy the value */
unittest
{
Optional!(int) x = 3;
Optional!(int) y;
assert(x);
assert(!y);
y = x;
assert(&x != &y);
assert(x);
assert(y);
y = 12;
assert(x.m_value.value != y.m_value.value);
assert(*y == 12);
Optional!(int) z;
x = z;
assert(!x);
assert(!z);
assert(y);
}