我即将编写一个解析器来逐行读取文本文件到不同类型的结构中,并将这些结构提供给回调(观察者或访问者 - 还不确定)。
该文本文件包含MT-940数据 - SWIFT银行对账单。
这些行包含一个标记,用于指定类型和一些字段 - 例如日期 - 应该被解析为我的消息的类型安全成员。其中一些字段是可选的 - 所以我的问题是:如何在D中表示可选值。
C ++提供了你可能知道的boost :: optional之类的东西。
我目前通过自己实现一个Optional(T)来解决这个问题(参见本文末尾的代码)。它是一个包含ValueHolder实例的结构,该实例可能为null - 这标记了没有赋值的情况。我覆盖了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);
}