在D语言中表示可选值

6

我即将编写一个解析器,按行读取文本文件并将其转换为不同类型的结构体,并将这些结构体传递给回调函数(观察者或访问者 - 尚不确定)。

文本文件包含MT-940数据 - SWIFT银行对账单。

这些行由指定类型和一些字段(例如日期)的标记组成,应将这些字段解析为我的消息的类型安全成员。其中一些字段是可选的 - 所以我的问题是:如何在D中表示可选值。

C ++提供了很多像boost :: optional这样的东西,你可能知道。

我目前通过自己实现Optional(T)来解决此问题(请参见本帖子末尾的代码)。它是一个包含ValueHolder实例的结构体,该实例可能为null - 表示未分配任何值的情况。我重写了复制构造函数和赋值运算符以创建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);
}
1个回答

10

对于可选值,D标准库在std.typecons模块中提供了Nullable结构模板。


既然我知道了它...它变得如此显而易见 :) 谢谢 - duselbaer
1
在使用 Nullable 时应该小心,因为它允许隐式转换到包装类型,例如,如果你有一个 Nullable!int ni,编译器不会阻止你执行 int n = ni。如果 ni 是 "null",这将在运行时抛出异常。 - Meta
1
@Meta 它不会抛出异常,而是进行断言。但是,当您尝试将 Nullable!T 用作 T 时,它确实会检查其是否为 "null"。 - Jonathan M Davis
谢谢你的提示...我预料到会有这样的情况。 - duselbaer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接