// Nullable,如何更好工作?技术上是`安全`的,但真不是.
module turducken;
import std.algorithm;
import std.datetime;
// 如何在`邪恶类型`上,早期解除绑定,并再后期绑定
// Turducken是答案.
// 先,设置舞台,值构类型
struct S
{
// 有一个引用不变数据的不变值字段
immutable int[] i;
// SysTime:过去和我冲突
SysTime st;
// 无默认
@disable this();
// 违反其不变量的.init
bool properlyInitialized = false;
invariant { assert(properlyInitialized); }
// 重载复制赋值,可禁止复制赋值.
void opAssign(S) { assert(false); }
// 为确认每个构造函数调用都匹配析构函数调用,它计算引用
int *refs;
this(int* refs)
pure @safe @nogc
{
this.properlyInitialized = true;
this.refs = refs;
(*refs)++;
}
this(this)
pure @safe @nogc
{ (*refs)++; }
// 既然定义了析构函数,我们肯定会,断定已破坏`.init`.
~this()
pure @safe @nogc
in(refs)
out(; *refs >= 0)
do { (*refs)--; }
}
// 挑战!
//函数为:
pure // pure,
@safe // safe,
@nogc // 及nogc:
unittest
{
// 干后期绑定和早期解除绑定
// 准备
// (验证)
int refs;
// (欺骗)
int* refsp = () @trusted { return &refs; }();
{
// 从默认初化变量开始
Turducken!S magic;
// 绑定到已构造值
magic.bind(S(refsp));
// 只一份
assert(refs == 1);
// 为了开心,绑定它
magic.bind(S(refsp));
// 仍然只有一个副本
assert(refs == 1);
// 包含的值一切正常
assert(magic.value.properlyInitialized);
// 域结束前解除绑定
magic.unbind;
// S离开了
assert(refs == 0);
}
// 只析构一次,正确.
assert(refs == 0);
}
// 如何完成
// Turducken!
struct Turducken(T)
{
// 美味中心
alias Chicken = T;
//Union确保不调用T析构函数
union Duck
{
Chicken chicken; //
}
//确保可用moveEmplace及神奇(违反常)的memcpy的构
struct Turkey
{
Duck duck;
}
Turkey store = Turkey.init; // 火鸡店
bool set = false;
// 插入吸管,进入中心
@property ref T value() in(set) { return store.duck.chicken; }
// 特制的酱汁
void bind(T value)
{
// 为防几秒后回来,清理
unbind;
//制作析构器保护的副本来粘贴在我们商店中
Turkey wrapper = Turkey(Duck(value));
// 忽略常,遍历数据.
() @trusted { moveEmplace(wrapper, store); }();
set = true;
}
// 调味品
void unbind()
{
if (set)
{
static if (is(T == struct)) {
destroy(value);
}
set = false;
}
}
// 因为已经避免了值受D的监视,
// 必须手动清理
~this()
{
unbind;
}
}