// 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;
}
}