std.typecons
В этом модуле реализовано множество конструкторов типов, то есть шаблонов, которые позволяют создавать новые, полезные типы общего назначения.
| Категория | Функции |
|---|---|
| Кортеж | isTuple Tuple tuple reverse |
| Флаги | BitFlags isBitFlagEnum Flag No Yes |
| Выделение памяти | RefCounted refCounted RefCountedAutoInitialize scoped Unique |
| Генерация кода | AutoImplement BlackHole generateAssertTrap generateEmptyFunction WhiteHole |
| Возможные значения NULL | Nullable nullable NullableRef nullableRef |
| Прокси | Proxy rebindable Rebindable ReplaceType unwrap wrap |
| Типы | alignForSize Ternary Typedef TypedefType UnqualRef |
- Лицензия:
- Boost License 1.0.
- Исходный код
- std/typecons.d
- Авторы:
- Andrei Alexandrescu, Bartosz Milewski, Don Clugston, Shin Fujishiro, Kenji Hara
- Примеры:
-
// value tuples alias Coord = Tuple!(int, "x", int, "y", int, "z"); Coord c; c[1] = 1; // access by index c.z = 1; // access by given name writeln(c); // Coord(0, 1, 1) // names can be omitted alias DicEntry = Tuple!(string, string); // tuples can also be constructed on instantiation writeln(tuple(2, 3, 4)[1]); // 3 // construction on instantiation works with names too writeln(tuple!("x", "y", "z")(2, 3, 4).y); // 3 // Rebindable references to const and immutable objects { class Widget { void foo() const @safe {} } const w1 = new Widget, w2 = new Widget; w1.foo(); // w1 = w2 would not work; can't rebind const object auto r = Rebindable!(const Widget)(w1); // invoke method as if r were a Widget object r.foo(); // rebind r to refer to another object r = w2; }
- struct Unique(T);
-
Капсулирует уникальную собственность ресурса.
Когда
Unique!Tвыходит за пределы области видимости, он вызоветdestroyдля ресурсаT, который он управляет, если он не передан. Важным следствиемdestroyявляется то, что он вызовет деструктор ресурсаT. Управляемые СУБД ссылки не гарантируются как действительные во время вызова деструктора, но другие членыT, такие как дескрипторы файлов или указатели наmallocпамять, останутся действительными во время вызова деструктора. Это позволяет ресурсуTосвободить или очистить любые ресурсы, не управляемые СУБД.
Если желательно сохранитьUnique!Tза пределами исходной области видимости, то он может быть передан. Передача может быть явной, вызвавrelease, или неявной, при возвращении Unique из функции. РесурсTможет быть объектом полиморфного класса или экземпляром интерфейса, в этом случае Unique также ведет себя полиморфно.
ЕслиT— это тип значения, тоUnique!Tбудет реализовано как ссылка наT.- Примеры:
-
static struct S { int i; this(int i){this.i = i;} } Unique!S produce() { // Construct a unique instance of S on the heap Unique!S ut = new S(5); // Implicit transfer of ownership return ut; } // Borrow a unique resource by ref void increment(ref Unique!S ur) { ur.i++; } void consume(Unique!S u2) { writeln(u2.i); // 6 // Resource automatically deleted here } Unique!S u1; assert(u1.isEmpty); u1 = produce(); increment(u1); writeln(u1.i); // 6 //consume(u1); // Error: u1 is not copyable // Transfer ownership of the resource consume(u1.release); assert(u1.isEmpty);
- alias RefT = T;
-
Представляет ссылку на
T. Преобразуется вT*еслиTявляется типом значения. - Unique!T create(A...)(auto ref A args)
Constraints: if (__traits(compiles, new T(args))); -
Позволяет безопасно создать
Unique. Он создает ресурс и гарантирует уникальную собственность на него (еслиTне публикует псевдонимыthis).- Примечание
- Вложенные структуры/классы создать нельзя.
- Параметры:
A argsАргументы для передачи в конструктор T.static class C {} auto u = Unique!(C).create();
- this(RefT p);
-
Конструктор, принимающий rvalue. Он гарантирует уникальность, пока rvalue не является просто представлением lvalue (например, преобразование). Типичное использование:
Unique!Foo f = new Foo;
- this(ref RefT p);
-
Конструктор, принимающий lvalue. Он обнуляет свой источник. Обнуление гарантирует уникальность, пока не существует предыдущих псевдонимов к источнику.
- this(U)(Unique!U u)
Constraints: if (is(u.RefT : RefT)); -
Конструктор, принимающий
Uniqueтипа, преобразуемого в наш тип.Обычно используется для передачи
Uniquervalue производного типа вUniqueбазового типа.- Пример
class C : Object {} Unique!C uc = new C; Unique!Object uo = uc.release; - void opAssign(U)(Unique!U u)
Constraints: if (is(u.RefT : RefT)); -
Передача владения от
Uniqueтипа, преобразуемого в наш тип. - const @property bool isEmpty();
-
Возвращает, существует ли ресурс.
- Unique release();
-
Передача владения
Uniquervalue. Обнуляет текущее содержимое. То же самое, что вызов std.algorithm.move на нём.
- struct Tuple(Specs...) if (distinctFieldNames!Specs);
-
Кортеж значений, например,
Tuple!(int, string)— это запись, которая хранитintиstring.Tupleможно использовать для группировки значений, особенно при возвращении нескольких значений из функции. ЕслиobjявляетсяTuple, отдельные члены доступны с синтаксисомobj[0]для первого поля,obj[1]для второго и т. д.- См. также:
-
tuple.
- Параметры:
Specs Список типов (и необязательно имён членов), которые содержит кортеж.
- Примеры:
-
Tuple!(int, int) point; // assign coordinates point[0] = 5; point[1] = 6; // read coordinates auto x = point[0]; auto y = point[1];
- Примеры:
- В
Tupleчлены могут быть именованными. Допускается смешивание именованных и безымянных членов. Вышеуказанный метод всё ещё применим ко всем полям.alias Entry = Tuple!(int, "index", string, "value"); Entry e; e.index = 4; e.value = "Hello"; writeln(e[1]); // "Hello" writeln(e[0]); // 4
- Примеры:
- Кортеж с именованными полями — это отдельный тип от кортежа с безымянными полями, то есть каждое именование даёт отдельный тип для
Tuple. ДваTupleотличающиеся только именами, всё ещё являются отдельными, даже если у них может быть одинаковая структура.Tuple!(int, "x", int, "y") point1; Tuple!(int, int) point2; assert(!is(typeof(point1) == typeof(point2)));
- Примеры:
- Использование кортежей как диапазонов
import std.algorithm.iteration : sum; import std.range : only; auto t = tuple(1, 2); writeln(t.expand.only.sum); // 3
- Примеры:
- Конкатенация кортежей
import std.meta : AliasSeq; auto t = tuple(1, "2") ~ tuple(ushort(42), true); static assert(is(t.Types == AliasSeq!(int, string, ushort, bool))); writeln(t[1]); // "2" writeln(t[2]); // 42 writeln(t[3]); // true
- alias Types = staticMap!(extractType, fieldSpecs);
-
Типы компонентов
Tuple. - alias fieldNames = staticMap!(extractName, fieldSpecs);
-
Имена компонентов
Tuple. У безименных полей имена пусты.- Примеры:
-
import std.meta : AliasSeq; alias Fields = Tuple!(int, "id", string, float); static assert(Fields.fieldNames == AliasSeq!("id", "", ""));
- Types expand;
-
Используйте
t.expandдляTupletразвёртывания в компоненты. Результатexpandбудет таким, как будто компонентыTupleперечислены в качестве списка значений. (ОбычноTupleдействует как одно значение.)- Примеры:
-
auto t1 = tuple(1, " hello ", 'a'); writeln(t1.toString()); // `Tuple!(int, string, char)(1, " hello ", 'a')` void takeSeveralTypes(int n, string s, bool b) { assert(n == 4 && s == "test" && b == false); } auto t2 = tuple(4, "test", false); //t.expand acting as a list of values takeSeveralTypes(t2.expand);
- this(Types values);
-
Конструктор, принимающий по одному значению для каждого поля.
- Параметры:
Types valuesСписок значений, которые имеют тот же тип, что и в поле TypesданногоTuple, или могут быть неявным образом преобразованы к этим типам. Они должны быть в том же порядке, что и вTypes.
- Примеры:
-
alias ISD = Tuple!(int, string, double); auto tup = ISD(1, "test", 3.2); writeln(tup.toString()); // `Tuple!(int, string, double)(1, "test", 3.2)`
- this(U, size_t n)(U[n] values)
Constraints: if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types)); -
Конструктор, принимающий совместимый массив.
- Параметры:
U[n] valuesСовместимый статический массив для построения Tuple. Срезы массивов не поддерживаются.
- Примеры:
-
int[2] ints; Tuple!(int, int) t = ints;
- this(U)(U another)
Constraints: if (areBuildCompatibleTuples!(typeof(this), U)); -
Конструктор, принимающий совместимый
Tuple. ДваTupleсовместимы если они имеют одинаковую длину и для каждого типаTслева соответствующий типUсправа может быть неявным образом преобразован кT.- Параметры:
U anotherСовместимый Tupleдля построения. Его тип должен быть совместим с типом целевогоTuple.
- Примеры:
-
alias IntVec = Tuple!(int, int, int); alias DubVec = Tuple!(double, double, double); IntVec iv = tuple(1, 1, 1); //Ok, int can implicitly convert to double DubVec dv = iv; //Error: double cannot implicitly convert to int //IntVec iv2 = dv;
- bool opEquals(R)(R rhs)
Constraints: if (areCompatibleTuples!(typeof(this), R, "=="));
const bool opEquals(R)(R rhs)
Constraints: if (areCompatibleTuples!(typeof(this), R, "=="));
bool opEquals(R...)(auto ref R rhs)
Constraints: if (R.length > 1 && areCompatibleTuples!(typeof(this), Tuple!R, "==")); -
Сравнение на равенство. Два
Tupleсчитаются равными если они соответствуют следующим критериям:- Каждая пара
Tupleимеет одинаковую длину. - Для каждого типа
Tслева и каждого типаUсправа значения типаTмогут быть сравнены со значениями типаU. - Для каждого значения
v1слева и каждого значенияv2справа выражениеv1 == v2истинно.
- Параметры:
R rhsTupleдля сравнения. Он должен соответствовать критериям сравненияTuple.
- Возвращает:
- true, если обе
Tupleравны, иначе false.
- Примеры:
-
Tuple!(int, string) t1 = tuple(1, "test"); Tuple!(double, string) t2 = tuple(1.0, "test"); //Ok, int can be compared with double and //both have a value of 1 writeln(t1); // t2
- Каждая пара
- int opCmp(R)(R rhs)
Constraints: if (areCompatibleTuples!(typeof(this), R, "<"));
const int opCmp(R)(R rhs)
Constraints: if (areCompatibleTuples!(typeof(this), R, "<")); -
Сравнение для упорядочивания.
- Параметры:
R rhsTupleдля сравнения. Он должен соответствовать критериям сравненияTuple.
- Возвращает:
- Для любых значений
v1справа иv2слева:- Отрицательное целое число, если выражение
v1 < v2истинно. - Положительное целое число, если выражение
v1 > v2истинно. - 0, если выражение
v1 == v2истинно.
- Отрицательное целое число, если выражение
- Примеры:
- Первое
v1, для которогоv1 > v2истинно, определяет результат. Это может привести к неожиданному поведению.auto tup1 = tuple(1, 1, 1); auto tup2 = tuple(1, 100, 100); assert(tup1 < tup2); //Only the first result matters for comparison tup1[0] = 2; assert(tup1 > tup2);
- auto opBinary(string op, T)(auto ref T t)
Constraints: if (op == "~" && !(is(T : U[], U) && isTuple!U));
auto opBinaryRight(string op, T)(auto ref T t)
Constraints: if (op == "~" && !(is(T : U[], U) && isTuple!U)); -
Объединение кортежей. Объединение кортежей разрешено только в том случае, если все именованные поля различны (никакое именованное поле этого кортежа не встречается в
tи ни одно именованное полеtне встречается в этом кортеже).- Параметры:
T tTupleдля объединения
- Возвращает:
- Объединение этого кортежа и
t
- ref Tuple opAssign(R)(auto ref R rhs)
Constraints: if (areCompatibleTuples!(typeof(this), R, "=")); -
Присваивание из другого
Tuple.- Параметры:
R rhsИсточник Tupleдля присваивания. Каждый элемент исходногоTupleдолжен быть неявным образом присваиваемым к соответствующему элементу целевогоTuple.
- inout ref auto rename(names...)() return
Constraints: if (names.length == 0 || allSatisfy!(isSomeString, typeof(names))); -
Переименовывает элементы
Tuple.renameиспользует переданныеnamesи возвращает новыйTupleс этими именами, при этом содержимое не изменяется. Если передано меньше имён, чем членовTuple, то оставшиеся члены не изменяются. Пустая строка удалит имя этого члена. Ошибка компиляции при передаче большего количества имён, чем членовTuple.- Примеры:
-
auto t0 = tuple(4, "hello"); auto t0Named = t0.rename!("val", "tag"); writeln(t0Named.val); // 4 writeln(t0Named.tag); // "hello" Tuple!(float, "dat", size_t[2], "pos") t1; t1.pos = [2, 1]; auto t1Named = t1.rename!"height"; t1Named.height = 3.4f; writeln(t1Named.height); // 3.4f writeln(t1Named.pos); // [2, 1] t1Named.rename!"altitude".altitude = 5; writeln(t1Named.height); // 5 Tuple!(int, "a", int, int, "c") t2; t2 = tuple(3,4,5); auto t2Named = t2.rename!("", "b"); // "a" no longer has a name static assert(!__traits(hasMember, typeof(t2Named), "a")); writeln(t2Named[0]); // 3 writeln(t2Named.b); // 4 writeln(t2Named.c); // 5 // not allowed to specify more names than the tuple has members static assert(!__traits(compiles, t2.rename!("a","b","c","d"))); // use it in a range pipeline import std.range : iota, zip; import std.algorithm.iteration : map, sum; auto res = zip(iota(1, 4), iota(10, 13)) .map!(t => t.rename!("a", "b")) .map!(t => t.a * t.b) .sum; writeln(res); // 68 const tup = Tuple!(int, "a", int, "b")(2, 3); const renamed = tup.rename!("c", "d"); writeln(renamed.c + renamed.d); // 5
- inout ref auto rename(alias translate)()
Constraints: if (is(typeof(translate) : V[K], V, K) && isSomeString!V && (isSomeString!K || is(K : size_t))); -
Перегрузка
rename, принимающая ассоциативный массивtranslateв качестве шаблона параметра, где ключи — либо имена, либо индексы меняемых членов, а новые имена — соответствующие значения. Каждый ключ вtranslateдолжен быть именем членаtuple. Те же правила для пустых строк применяются, что и для перегрузкиrenameс переменным шаблоном.- Примеры:
-
//replacing names by their current name Tuple!(float, "dat", size_t[2], "pos") t1; t1.pos = [2, 1]; auto t1Named = t1.rename!(["dat": "height"]); t1Named.height = 3.4; writeln(t1Named.pos); // [2, 1] t1Named.rename!(["height": "altitude"]).altitude = 5; writeln(t1Named.height); // 5 Tuple!(int, "a", int, "b") t2; t2 = tuple(3, 4); auto t2Named = t2.rename!(["a": "b", "b": "c"]); writeln(t2Named.b); // 3 writeln(t2Named.c); // 4 const t3 = Tuple!(int, "a", int, "b")(3, 4); const t3Named = t3.rename!(["a": "b", "b": "c"]); writeln(t3Named.b); // 3 writeln(t3Named.c); // 4
- Примеры:
-
//replace names by their position Tuple!(float, "dat", size_t[2], "pos") t1; t1.pos = [2, 1]; auto t1Named = t1.rename!([0: "height"]); t1Named.height = 3.4; writeln(t1Named.pos); // [2, 1] t1Named.rename!([0: "altitude"]).altitude = 5; writeln(t1Named.height); // 5 Tuple!(int, "a", int, "b", int, "c") t2; t2 = tuple(3, 4, 5); auto t2Named = t2.rename!([0: "c", 2: "a"]); writeln(t2Named.a); // 5 writeln(t2Named.b); // 4 writeln(t2Named.c); // 3
- inout @property ref @trusted inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)()
Constraints: if (from <= to && (to <= Types.length)); -
Возвращает срез этого
Tupleпо ссылке.- Параметры:
from Позиция начала среза. to Позиция конца среза (исключительно).
- Возвращает:
- Новый
Tuple, являющийся срезом с[from, to)из исходного. Он имеет те же типы и значения, что и диапазон[from, to)в исходном.
- Примеры:
-
Tuple!(int, string, float, double) a; a[1] = "abc"; a[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); // https://issues.dlang.org/show_bug.cgi?id=15645 Tuple!(int, short, bool, double) b; static assert(!__traits(compiles, b.slice!(2, 4)));
- const nothrow @safe size_t toHash();
-
Создаёт хеш этого
Tuple.- Возвращает:
- Хеш этого
Tuple.
- const string toString()();
-
Преобразует в строку.
- Возвращает:
- Строковое представление этого
Tuple.
- const void toString(DG)(scope DG sink);
const void toString(DG, Char)(scope DG sink, ref scope const FormatSpec!Char fmt);
-
Форматирует
Tupleс помощью%s,%(inner%)или%(inner%|sep%).Форматы, поддерживаемые Tuple Формат Описание %sФормат, подобный
Tuple!(types)(elements formatted with %s each).%(inner%)Формат
innerприменяется к расширенномуTuple, поэтому он может содержать столько же форматов, сколько полей уTuple.%(inner%|sep%)Формат
inner— один формат, который применяется ко всем полямTuple. Внутренний формат должен быть совместим со всеми ними.- Параметры:
DG sinkДелегат, принимающий charFormatSpec!Char fmtstd.format.FormatSpec
- Примеры:
-
import std.format : format; Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; // Default format writeln(format("%s", tuple("a", 1))); // `Tuple!(string, int)("a", 1)` // One Format for each individual component writeln(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10))); // `0x1 v 1.0000 w 0xa` writeln(format("%#x v %.4f w %#x", tuple(1, 1.0, 10).expand)); // `0x1 v 1.0000 w 0xa` // One Format for all components // `>abc< & >1< & >2.3< & >[4, 5]<` writeln(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5]))); // Array of Tuples writeln(format("%(%(f(%d) = %.1f%); %)", tupList)); // `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`
- Примеры:
-
import std.exception : assertThrown; import std.format : format, FormatException; // Error: %( %) missing. assertThrown!FormatException( format("%d, %f", tuple(1, 2.0)) == `1, 2.0` ); // Error: %( %| %) missing. assertThrown!FormatException( format("%d", tuple(1, 2)) == `1, 2` ); // Error: %d inadequate for double assertThrown!FormatException( format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` );
-
- auto reverse(T)(T t)
Ограничения: если (isTuple!T); -
Создает копию
Tupleс полями в обратном порядке.- Параметры:
T tКопируемая Tuple
- Возвращает:
- Новый
Tuple.
- Примеры:
-
auto tup = tuple(1, "2"); writeln(tup.reverse); // tuple("2", 1)
- template tuple(Names...)
-
Создает объект
Tuple, инициализированный в соответствии с заданными аргументами.- Параметры:
Names Необязательный список строк, задающих имена каждого последующего поля Tupleили список типов, к которым преобразуются элементы. Для списка имён каждое имя соответствует соответствующему полю, заданномуArgs. Имя не обязательно должно быть указано для каждого поля, но поскольку имена должны следовать в порядке, невозможно пропустить одно поле и назвать следующее за ним. Для списка типов должно быть ровно столько же типов, сколько параметров.
- Примеры:
-
auto value = tuple(5, 6.7, "hello"); writeln(value[0]); // 5 writeln(value[1]); // 6.7 writeln(value[2]); // "hello" // Field names can be provided. auto entry = tuple!("index", "value")(4, "Hello"); writeln(entry.index); // 4 writeln(entry.value); // "Hello"
- auto tuple(Args...)(Args args);
-
- Параметры:
Args argsЗначения для инициализации Tuple. ТипTupleбудет определён из типов заданных значений.
- Возвращает:
- Новый
Tupleс типом, определённым из заданных аргументов.
- enum auto isTuple(T);
-
Возвращает
trueтогда и только тогда, когдаTявляется экземпляромstd.typecons.Tuple.- Параметры:
T Тип для проверки.
- Возвращает:
- true, если
T— типTuple, false в противном случае.
- Примеры:
-
static assert(isTuple!(Tuple!())); static assert(isTuple!(Tuple!(int))); static assert(isTuple!(Tuple!(int, real, string))); static assert(isTuple!(Tuple!(int, "x", real, "y"))); static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
- template Rebindable(T) if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
-
Rebindable!(T)— простой и эффективный оболочка, которая ведет себя как объект типаT, за исключением того, что вы можете переназначить её для ссылки на другой объект. Для полноты,Rebindable!(T)алиасится вTеслиT— тип объекта, не являющегося константным.Вы можете использовать
Rebindableкогда вам нужен изменяемый хранилище, ссылающийся на объектыconst, например массив ссылок, которые необходимо отсортировать на месте.Rebindableне нарушает корректность системы типов D и не несёт рисков, обычно связанных сcast.- Параметры:
T Объект, интерфейс, тип массива или ассоциативного массива.
- Примеры:
- Обычные ссылки на объекты
constпереназначить нельзя.class Widget { int x; int y() @safe const { return x; } } const a = new Widget; // Fine a.y(); // error! can't modify const a // a.x = 5; // error! can't modify const a // a = new Widget;
- Примеры:
- Однако,
Rebindable!(Widget)позволяет переназначить, в остальном ведя себя точно какconst Widget.class Widget { int x; int y() const @safe { return x; } } auto a = Rebindable!(const Widget)(new Widget); // Fine a.y(); // error! can't modify const a // a.x = 5; // Fine a = new Widget;
- Rebindable!T rebindable(T)(T obj)
Ограничения: если (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T); -
Функция-удобство для создания
Rebindableс автоматическим определением типа.- Параметры:
T objСсылка на объект, интерфейс, ассоциативный массив или срез массива для инициализации Rebindable
- Возвращает:
- Новый
Rebindable, инициализированный заданной ссылкой.
- Примеры:
-
class C { int payload; this(int p) { payload = p; } } const c = new C(1); auto c2 = c.rebindable; writeln(c2.payload); // 1 // passing Rebindable to rebindable c2 = c2.rebindable; c2 = new C(2); writeln(c2.payload); // 2 const c3 = c2.get; writeln(c3.payload); // 2
- Rebindable!T rebindable(T)(Rebindable!T obj);
-
Эта функция просто возвращает переданный объект
Rebindable. Она полезна в случаях с общей программированием, когда заданный объект может быть как обычнойclass, так иRebindable.- Параметры:
Rebindable!T objЭкземпляр Rebindable!T.
- Возвращает:
-
objбез изменений.
- Примеры:
-
class C { int payload; this(int p) { payload = p; } } const c = new C(1); auto c2 = c.rebindable; writeln(c2.payload); // 1 // passing Rebindable to rebindable c2 = c2.rebindable; writeln(c2.payload); // 1
- template UnqualRef(T) if (is(T == class) || is(T == interface))
-
Аналогично
Rebindable!(T), но удаляет все квалификаторы из ссылки, а не только константность/неизменяемость. Основной случай использования — с общими ресурсами (иметь локальную ссылку на общие данные класса).- Параметры:
T Тип класса или интерфейса.
- Примеры:
-
class Data {} static shared(Data) a; static UnqualRef!(shared Data) b; import core.thread; auto thread = new core.thread.Thread({ a = new shared Data(); b = new shared Data(); }); thread.start(); thread.join(); assert(a !is null); assert(b is null);
- string alignForSize(E...)(const char[][] names...);
-
Упорядочивает предоставленные члены для минимизации размера, сохраняя выравнивание. Выравнивание не всегда оптимально для 80-битовых чисел с плавающей точкой, ни для структур, объявленных как align(1).
- Параметры:
E Список типов для выравнивания, представляющих поля агрегата, такого как structилиclasschar[][] namesИмена полей, которые необходимо выровнять.
- Возвращает:
- Строка, которая будет добавлена в агрегат, такой как
structилиclass.
- Примеры:
-
struct Banner { mixin(alignForSize!(byte[6], double)(["name", "height"])); }
- struct Nullable(T);
auto nullable(T)(T t);
-
Определяет значение, связанное с уникальным состоянием «null», которое обозначает отсутствие значения. Если объект
Nullable!Tсоздан по умолчанию, он находится в состоянии null. Присвоение значения делает его не-null. Вызовnullifyможет снова установить его в состояние null.Практически
Nullable!TхранитTиbool.- Примеры:
-
struct CustomerRecord { string name; string address; int customerNum; } Nullable!CustomerRecord getByName(string name) { //A bunch of hairy stuff return Nullable!CustomerRecord.init; } auto queryResult = getByName("Doe, John"); if (!queryResult.isNull) { //Process Mr. Doe's customer record auto address = queryResult.get.address; auto customerNum = queryResult.get.customerNum; //Do some things with this customer's info } else { //Add the customer to the database }
- Примеры:
-
import std.exception : assertThrown; auto a = 42.nullable; assert(!a.isNull); writeln(a.get); // 42 a.nullify(); assert(a.isNull); assertThrown!Throwable(a.get);
- inout this(inout T value);
-
Конструктор, инициализирующий
thisзначениемvalue.- Параметры:
T valueЗначение, используемое для инициализации Nullable.
- const bool opEquals()(auto ref const(typeof(this)) rhs);
const bool opEquals(U)(auto ref const(U) rhs)
Constraints: if (!is(U : typeof(this)) && is(typeof(this.get == rhs))); -
Если оба значения null, они равны. Если одно значение null, а другое нет, они не равны. Если оба значения не null, они равны, если их значения равны.
- Примеры:
-
Nullable!int empty; Nullable!int a = 42; Nullable!int b = 42; Nullable!int c = 27; writeln(empty); // empty writeln(empty); // Nullable!int.init assert(empty != a); assert(empty != b); assert(empty != c); writeln(a); // b assert(a != c); assert(empty != 42); writeln(a); // 42 assert(c != 42);
- string toString();
const string toString();
void toString(W)(ref W writer, ref scope const FormatSpec!char fmt)
Constraints: if (isOutputRange!(W, char));
const void toString(W)(ref W writer, ref scope const FormatSpec!char fmt)
Constraints: if (isOutputRange!(W, char)); -
Возвращает строку
"Nullable.null", еслиisNullимеет значениеtrue. В противном случае результат эквивалентен вызовуstd.format.formattedWriteдля внутреннего значения.- Параметры:
W writerОбъект, принимающий диапазон вывода FormatSpec!char fmtstd.format.FormatSpec, используемый для представления значения, если this Nullable не null
- Возвращает:
- Строку
string, еслиwriterиfmtне установлены;voidв противном случае.
- const pure nothrow @property @safe bool isNull();
-
Проверяет, находится ли
thisв состоянии null.- Возвращает:
- true, если
thisнаходится в состоянии null, иначе false.
- Примеры:
-
Nullable!int ni; assert(ni.isNull); ni = 0; assert(!ni.isNull);
- void nullify()();
-
Принудительно устанавливает
thisв состояние null.- Примеры:
-
Nullable!int ni = 0; assert(!ni.isNull); ni.nullify(); assert(ni.isNull);
- void opAssign()(T value);
-
Присваивает
valueвнутреннему состоянию. Если присвоение успешно,thisстановится не-null.- Параметры:
T valueЗначение типа Tдля присвоенияNullable.
- void opAssign()(Nullable!T value);
-
Если value null, устанавливает this в null, в противном случае присваивает
value.getвнутреннему состоянию. Если присвоение успешно,thisстановится не-null.- Параметры:
Nullable!T valueЗначение типа Nullable!Tдля присвоенияNullable.
- Примеры:
- Если this
Nullableоборачивает тип, уже имеющий значение null (например, указатель), то присвоение null этомуNullableничем не отличается от присвоения любого другого значения типаT, и полученный код будет выглядеть очень странно. Сильно рекомендуется избегать этого, используя версиюNullableсо дополнительным параметромnullValue.
- inout pure nothrow @property ref @safe inout(T) get();
inout pure nothrow @property @safe inout(T) get()(inout(T) fallback);
inout pure nothrow @property @safe auto get(U)(inout(U) fallback); -
Получает значение, если оно не null. Если
thisнаходится в состоянии null, и необязательный параметрfallbackбыл предоставлен, он будет возвращён. Безfallback, вызовgetсо состоянием null недопустим.Когда тип fallback отличается от типа Nullable,
get(T)возвращает общий тип.- Параметры:
inout(T) fallbackЗначение, возвращаемое в случае, если Nullablenull.
- Возвращает:
- Значение, хранящееся внутри
Nullable.
- struct Nullable(T, T nullValue);
auto nullable(alias nullValue, T)(T t)
Constraints: if (is(typeof(nullValue) == T)); -
Аналогично
Nullable!T, но состояние null определено как конкретное значение. Например,Nullable!(uint, uint.max)этоuint, который использует значениеuint.maxдля обозначения состояния null.Nullable!(T, nullValue)более эффективен с точки зрения памяти, чемNullable!T, так как ему не нужно хранить дополнительноеbool.- Параметры:
T Тип оборачиваемого значения, для которого Nullable предоставляет значение null. nullValue Значение null, обозначающее состояние null этого Nullable. Должно быть типаT.
- Примеры:
-
Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) { //Find the needle, returning -1 if not found return Nullable!(size_t, size_t.max).init; } void sendLunchInvite(string name) { } //It's safer than C... auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; auto pos = indexOf(coworkers, "Bob"); if (!pos.isNull) { //Send Bob an invitation to lunch sendLunchInvite(coworkers[pos]); } else { //Bob not found; report the error } //And there's no overhead static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof);
- Примеры:
-
import std.exception : assertThrown; Nullable!(int, int.min) a; assert(a.isNull); assertThrown!Throwable(a.get); a = 5; assert(!a.isNull); writeln(a); // 5 static assert(a.sizeof == int.sizeof);
- Примеры:
-
auto a = nullable!(int.min)(8); writeln(a); // 8 a.nullify(); assert(a.isNull);
- this(T value);
-
Конструктор, инициализирующий
thisзначениемvalue.- Параметры:
T valueЗначение, используемое для инициализации Nullable.
- const @property bool isNull();
-
Проверяет, находится ли
thisв состоянии null.- Возвращает:
- true, если
thisнаходится в состоянии null, иначе false.
- Примеры:
-
Nullable!(int, -1) ni; //Initialized to "null" state assert(ni.isNull); ni = 0; assert(!ni.isNull);
- void nullify()();
-
Принудительно устанавливает
thisв состояние null.- Примеры:
-
Nullable!(int, -1) ni = 0; assert(!ni.isNull); ni = -1; assert(ni.isNull);
- void opAssign()(T value);
-
Присваивает
valueвнутреннему состоянию. Если присвоение успешно,thisстановится не-null. Проверки на null не выполняются. Обратите внимание, что присвоение может оставитьthisв состоянии null.- Параметры:
T valueЗначение типа Tдля присвоенияNullable. Если оноnullvalue, внутреннее состояние этогоNullableбудет установлено в null.
- Примеры:
- Если этот
Nullableоборачивает тип, уже имеющий значение null (например, указатель), и это значение null не задано дляnullValue, то присвоение значения null этомуNullableничем не отличается от присвоения любого другого значения типаT, и полученный код будет выглядеть очень странно. Сильно рекомендуется избегать этого, используя «встроенное» значение null дляnullValue.
- inout @property ref inout(T) get();
-
Получает значение.
thisне должен быть в состоянии null. Эта функция также вызывается для неявного преобразования вT.- Предварительные условия
-
isNullдолжен бытьfalse.
- Возвращает:
- Значение, хранящееся внутри
Nullable.
- Примеры:
-
import std.exception : assertThrown, assertNotThrown; Nullable!(int, -1) ni; //`get` is implicitly called. Will throw //an error in non-release mode assertThrown!Throwable(ni == 0); ni = 0; assertNotThrown!Throwable(ni == 0);
- template apply(alias fun)
-
Распаковывает содержимое
Nullable, выполняет операцию и снова упаковывает. Не делает ничего, если isNull.При вызове на
Nullable,applyраспакует значение, содержащееся вNullable, передаёт его в предоставленную функцию и помещает результат в другойNullable(если необходимо). ЕслиNullablenull,applyвернёт null.- Параметры:
T t Nullablefun Функция, обрабатывающая содержимое nullable
- Возвращает:
-
fun(t.get).nullableесли!t.isNull, в противном случаеNullable.init. См. также: МонадMaybe
- Примеры:
-
alias toFloat = i => cast(float) i; Nullable!int sample; // apply(null) results in a null `Nullable` of the function's return type. Nullable!float f = sample.apply!toFloat; assert(sample.isNull && f.isNull); sample = 3; // apply(non-null) calls the function and wraps the result in a `Nullable`. f = sample.apply!toFloat; assert(!sample.isNull && !f.isNull); writeln(f.get); // 3.0f
- Примеры:
-
alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init; Nullable!int sample; // when the function already returns a `Nullable`, that `Nullable` is not wrapped. auto result = sample.apply!greaterThree; assert(sample.isNull && result.isNull); // The function may decide to return a null `Nullable`. sample = 3; result = sample.apply!greaterThree; assert(!sample.isNull && result.isNull); // Or it may return a value already wrapped in a `Nullable`. sample = 4; result = sample.apply!greaterThree; assert(!sample.isNull && !result.isNull); writeln(result.get); // 4
- struct NullableRef(T);
auto nullableRef(T)(T* t);
-
Точно так же, как
Nullable!T, за исключением того, что объект ссылается на значение, находящееся в другом месте памяти. Это означает, что присваивания перезаписывают начальное присвоенное значение. ВнутреннеNullableRef!Tхранит только указатель наT(т.е.Nullable!T.sizeof == (T*).sizeof).- Примеры:
-
import std.exception : assertThrown; int x = 5, y = 7; auto a = nullableRef(&x); assert(!a.isNull); writeln(a); // 5 writeln(x); // 5 a = 42; writeln(x); // 42 assert(!a.isNull); writeln(a); // 42 a.nullify(); writeln(x); // 42 assert(a.isNull); assertThrown!Throwable(a.get); assertThrown!Throwable(a = 71); a.bind(&y); writeln(a); // 7 y = 135; writeln(a); // 135
- pure nothrow @safe this(T* value);
-
Конструктор связывает
thisсvalue.- Параметры:
T* valueЗначение, которое нужно связать.
- pure nothrow @safe void bind(T* value);
-
Связывает внутреннее состояние с
value.- Параметры:
T* valueУказатель на значение типа Tдля привязки этогоNullableRef.
- Примеры:
-
NullableRef!int nr = new int(42); writeln(nr); // 42 int* n = new int(1); nr.bind(n); writeln(nr); // 1
- const pure nothrow @property @safe bool isNull();
-
Возвращает
trueтогда и только тогда, когдаthisнаходится в нулевом состоянии.- Возвращаемое значение:
- true, если
thisнаходится в нулевом состоянии, в противном случае false.
- Примеры:
-
NullableRef!int nr; assert(nr.isNull); int* n = new int(42); nr.bind(n); assert(!nr.isNull && nr == 42);
- pure nothrow @safe void nullify();
-
Принудительно переводит
thisв нулевое состояние.- Примеры:
-
NullableRef!int nr = new int(42); assert(!nr.isNull); nr.nullify(); assert(nr.isNull);
- void opAssign()(T value)
Constraints: if (isAssignable!T); -
Присваивает
valueвнутреннему состоянию.- Параметры:
T valueЗначение типа Tдля присваивания этомуNullableRef. Если внутреннее состояние этогоNullableRefне было инициализировано, в режиме, отличном от релизного, будет выброшено исключение.
- Примеры:
-
import std.exception : assertThrown, assertNotThrown; NullableRef!int nr; assert(nr.isNull); assertThrown!Throwable(nr = 42); nr.bind(new int(0)); assert(!nr.isNull); assertNotThrown!Throwable(nr = 42); writeln(nr); // 42
- inout pure nothrow @property ref @safe inout(T) get();
-
Получает значение.
thisне должно быть в нулевом состоянии. Эта функция также вызывается для неявного преобразования вT.- Примеры:
-
import std.exception : assertThrown, assertNotThrown; NullableRef!int nr; //`get` is implicitly called. Will throw //an error in non-release mode assertThrown!Throwable(nr == 0); nr.bind(new int(0)); assertNotThrown!Throwable(nr == 0);
- template BlackHole(Base)
-
BlackHole!Baseявляется подклассомBase, который автоматически реализует все абстрактные функции-члены вBaseкак функции «ничего не делать». Каждая автоматически реализованная функция просто возвращает значение по умолчанию для типа возвращаемого значения, не выполняя никаких действий.Название взято из модуля Perl Class::BlackHole от Шона М. Берка.
- Параметры:
Base Нефинальный класс для наследования BlackHole.
- См. также:
-
AutoImplement,generateEmptyFunction
- Примеры:
-
import std.math : isNaN; static abstract class C { int m_value; this(int v) { m_value = v; } int value() @property { return m_value; } abstract real realValue() @property; abstract void doSomething(); } auto c = new BlackHole!C(42); writeln(c.value); // 42 // Returns real.init which is NaN assert(c.realValue.isNaN); // Abstract functions are implemented as do-nothing c.doSomething();
- template WhiteHole(Base)
-
WhiteHole!Baseявляется подклассомBase, который автоматически реализует все абстрактные функции-члены как функции, которые всегда завершаются ошибкой. Эти функции просто выбрасываютErrorи никогда не возвращаются.Whiteholeполезна для перехвата использования функций-членов класса, которые не были реализованы.Название взято из модуля Perl Class::WhiteHole от Майкла Дж. Шверна.
- Параметры:
Base Нефинальный класс для наследования WhiteHole.
- См. также:
-
AutoImplement,generateAssertTrap
- Примеры:
-
import std.exception : assertThrown; static class C { abstract void notYetImplemented(); } auto c = new WhiteHole!C; assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error
- class AutoImplement(Base, alias how, alias what = isAbstractFunction) if (!is(how == class)): Base;
class AutoImplement(Interface, BaseClass, alias how, alias what = isAbstractFunction) if (is(Interface == interface) && is(BaseClass == class)): BaseClass, Interface; -
AutoImplementавтоматически реализует (по умолчанию) все абстрактные функции-члены в классе или интерфейсеBaseуказанным способом.Второй вариант
AutoImplementавтоматически реализуетInterface, наследовавшись отBaseClass.- Параметры:
how шаблон, который определяет, как будут реализованы/переопределены функции. Две переменные передаются в how: типBaseи псевдоним реализованной функции. Затемhowдолжен вернуть реализованное тело функции в виде строки. Сгенерированное тело функции может использовать следующие ключевые слова:-
a0,a1, …: аргументы, передаваемые в функцию; -
args: кортеж аргументов; -
self: псевдоним самой функции; -
parent: псевдоним переопределенной функции (если она есть).
// Prints log messages for each call to overridden functions. string generateLogger(C, alias fun)() @property { import std.traits; enum qname = C.stringof ~ "." ~ __traits(identifier, fun); string stmt; stmt ~= q{ struct Importer { import std.stdio; } }; stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`; static if (!__traits(isAbstractFunction, fun)) { static if (is(ReturnType!fun == void)) stmt ~= q{ parent(args); }; else stmt ~= q{ auto r = parent(args); Importer.writeln("--> ", r); return r; }; } return stmt; }what шаблон, который определяет, какие функции должны быть реализованы/переопределены. Аргумент передаётся в what: псевдоним нефинальной функции-члена вBase. Затемwhatдолжен вернуть булевое значение. Возвращатьtrueозначает, что переданная функция должна быть реализована/переопределена.// Sees if fun returns something. enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
-
- Примечание
- Сгенерированный код вставляется в область видимости модуля
std.typecons. Таким образом, любые полезные функции за пределамиstd.typeconsне могут быть использованы в сгенерированном коде. Чтобы обойти эту проблему, вы можетеimportнеобходимые вещи в локальной структуре, как это сделано в шаблонеgenerateLogger()в примере выше.
- Ошибки:
- Переменные аргументы конструкторов не передаются в суперкласс.
- Глубокое наследование интерфейса приводит к ошибке компиляции с сообщениями типа «Ошибка: функция std.typecons.AutoImplement!(Foo).AutoImplement.bar не переопределяет ни одну функцию». [Bugzilla 2525]
- Ключевое слово
parentна самом деле является делегатом на соответствующую функцию-член суперкласса. [Bugzilla 2540] - Использование параметра шаблона alias в
howи/илиwhatможет привести к странной ошибке компиляции. Для решения этой проблемы используйте параметр шаблона кортежа вместо него. [Bugzilla 4217]
- Примеры:
-
interface PackageSupplier { int foo(); int bar(); } static abstract class AbstractFallbackPackageSupplier : PackageSupplier { protected PackageSupplier default_, fallback; this(PackageSupplier default_, PackageSupplier fallback) { this.default_ = default_; this.fallback = fallback; } abstract int foo(); abstract int bar(); } template fallback(T, alias func) { import std.format : format; // for all implemented methods: // - try default first // - only on a failure run & return fallback enum fallback = q{ scope (failure) return fallback.%1$s(args); return default_.%1$s(args); }.format(__traits(identifier, func)); } // combines two classes and use the second one as fallback alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); class FailingPackageSupplier : PackageSupplier { int foo(){ throw new Exception("failure"); } int bar(){ return 2;} } class BackupPackageSupplier : PackageSupplier { int foo(){ return -1; } int bar(){ return -1;} } auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier()); writeln(registry.foo()); // -1 writeln(registry.bar()); // 2
- template generateEmptyFunction(C, func...)
enum string generateAssertTrap(C, func...); -
Предопределенные политики how для
AutoImplement. Эти шаблоны также используютсяBlackHoleиWhiteHoleсоответственно.- Примеры:
-
alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction); interface I { int foo(); string bar(); } auto i = new BlackHole!I(); // generateEmptyFunction returns the default value of the return type without doing anything writeln(i.foo); // 0 assert(i.bar is null);
- Примеры:
-
import std.exception : assertThrown; alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap); interface I { int foo(); string bar(); } auto i = new WhiteHole!I(); // generateAssertTrap throws an exception for every unimplemented function of the interface assertThrown!NotImplementedError(i.foo); assertThrown!NotImplementedError(i.bar);
- template wrap(Targets...) if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
template wrap(Targets...) if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
template unwrap(Target) if (isMutable!Target)
template unwrap(Target) if (!isMutable!Target) -
Поддержка структурно-ориентированных безопасных преобразований.
Если
Sourceимеет структурное соответствие сinterfaceTargets, wrap создаёт внутренний класс-обёртку, который наследуется отTargetsи обёрткиsrcобъект, затем возвращает его.
unwrapможет быть использован для извлечения объектов, которые были обернуты с помощьюwrap.- Примеры:
-
interface Quack { int quack(); @property int height(); } interface Flyer { @property int height(); } class Duck : Quack { int quack() { return 1; } @property int height() { return 10; } } class Human { int quack() { return 2; } @property int height() { return 20; } } Duck d1 = new Duck(); Human h1 = new Human(); interface Refleshable { int reflesh(); } // does not have structural conformance static assert(!__traits(compiles, d1.wrap!Refleshable)); static assert(!__traits(compiles, h1.wrap!Refleshable)); // strict upcast Quack qd = d1.wrap!Quack; assert(qd is d1); assert(qd.quack() == 1); // calls Duck.quack // strict downcast Duck d2 = qd.unwrap!Duck; assert(d2 is d1); // structural upcast Quack qh = h1.wrap!Quack; assert(qh.quack() == 2); // calls Human.quack // structural downcast Human h2 = qh.unwrap!Human; assert(h2 is h1); // structural upcast (two steps) Quack qx = h1.wrap!Quack; // Human -> Quack Flyer fx = qx.wrap!Flyer; // Quack -> Flyer assert(fx.height == 20); // calls Human.height // structural downcast (two steps) Quack qy = fx.unwrap!Quack; // Flyer -> Quack Human hy = qy.unwrap!Human; // Quack -> Human assert(hy is h1); // structural downcast (one step) Human hz = fx.unwrap!Human; // Flyer -> Human assert(hz is h1);
- Примеры:
-
import std.traits : FunctionAttribute, functionAttributes; interface A { int run(); } interface B { int stop(); @property int status(); } class X { int run() { return 1; } int stop() { return 2; } @property int status() { return 3; } } auto x = new X(); auto ab = x.wrap!(A, B); A a = ab; B b = ab; writeln(a.run()); // 1 writeln(b.stop()); // 2 writeln(b.status); // 3 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
- enum RefCountedAutoInitialize: int;
-
Варианты автоматической инициализации объекта
RefCounted(см. определениеRefCountedниже).- Примеры:
-
import core.exception : AssertError; import std.exception : assertThrown; struct Foo { int a = 42; } RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; writeln(rcAuto.refCountedPayload.a); // 42 assertThrown!AssertError(rcNoAuto.refCountedPayload); rcNoAuto.refCountedStore.ensureInitialized; writeln(rcNoAuto.refCountedPayload.a); // 42
- no
-
Не выполнять автоматическую инициализацию объекта
- yes
-
Выполнить автоматическую инициализацию объекта
- struct RefCounted(T, RefCountedAutoInitialize autoInit = RefCountedAutoInitialize.yes) if (!is(T == class) && !is(T == interface));
-
Определяет объект со ссылочным подсчётом, содержащий значение
Tв качестве полезной нагрузки.Экземпляр
RefCountedпредставляет собой ссылку на структуру, которая в данной документации называется хранилищем или структурой реализации хранилища. Хранилище содержит счётчик ссылок и полезную нагрузкуT.RefCountedиспользуетmallocдля выделения хранилища. По мере копирования экземпляровRefCountedили выхода их из области видимости, счётчик ссылок автоматически увеличивается или уменьшается. Когда счётчик ссылок становится равным нулю,RefCountedвызоветdestroyдля полезной нагрузки и вызоветfreeдля освобождения хранилища. Если полезная нагрузкаTсодержит ссылки на память, выделенную под управлением сборщика мусора,RefCountedдобавит её в память сборщика мусора, которая сканируется на указатели, и удалит её из сканирования сборщиком мусора до вызоваfreeдля хранилища.
Важным следствием работыdestroyявляется вызов деструктора полезной нагрузкиT. Ссылки, управляемые сборщиком мусора, не гарантированно останутся валидными во время вызова деструктора, но другие членыT, такие как дескрипторы файлов или указатели на памятьmalloc, останутся валидными во время вызова деструктора. Это позволяетTосвободить или очистить любые ресурсы, не управляемые сборщиком мусора, сразу после того, как счётчик ссылок достигнет нуля.
RefCountedнебезопасен и следует использовать с осторожностью. Ссылки на полезную нагрузку не должны выходить за пределы объектаRefCounted.
ОпцияautoInitобеспечивает автоматическую инициализацию хранилища. ОставлениеautoInit == RefCountedAutoInitialize.yes(по умолчанию) удобно, но влечёт за собой проверку при каждом доступе к полезной нагрузке. ЕслиautoInit == RefCountedAutoInitialize.no, код пользователя должен вызвать либоrefCountedStore.isInitialized, либоrefCountedStore.ensureInitializedперед попыткой доступа к полезной нагрузке. Пропуск этой операции приведёт к ошибке обращения к нулевому указателю.- Примеры:
-
// A pair of an `int` and a `size_t` - the latter being the // reference count - will be dynamically allocated auto rc1 = RefCounted!int(5); writeln(rc1); // 5 // No more allocation, add just one extra reference count auto rc2 = rc1; // Reference semantics rc2 = 42; writeln(rc1); // 42 // the pair will be freed when rc1 and rc2 go out of scope
- struct RefCountedStore;
-
RefCountedреализация хранилища.- const pure nothrow @nogc @property @safe bool isInitialized();
-
Возвращает
true, если и только если основное хранилище было выделено и инициализировано. - const pure nothrow @nogc @property @safe size_t refCount();
-
Возвращает значение счётчика ссылок, если хранилище выделено и инициализировано (положительное целое число), и
0в противном случае. - void ensureInitialized();
-
Гарантирует корректную инициализацию полезной нагрузки. Такой вызов обычно вставляется перед использованием полезной нагрузки.
- inout nothrow @property ref @safe inout(RefCountedStore) refCountedStore();
-
Возвращает структуру реализации хранилища.
- this(A...)(auto ref A args)
Constraints: if (A.length > 0);
this(T val); -
Конструктор, инициализирующий полезную нагрузку.
- Постусловие
-
refCountedStore.isInitialized
- void opAssign(typeof(this) rhs);
void opAssign(T rhs); -
Операторы присваивания
- @property ref @trusted T refCountedPayload() return;
inout pure nothrow @nogc @property ref @safe inout(T) refCountedPayload() return; -
Возвращает ссылку на полезную нагрузку. Если (autoInit == RefCountedAutoInitialize.yes), вызывает
refCountedStore.ensureInitialized. В противном случае просто выполняетassert(refCountedStore.isInitialized). Используется сalias refCountedPayload this;, чтобы вызывающие функции могли использовать объектRefCountedкакT.Первый перегрузка существует только если
autoInit == RefCountedAutoInitialize.yes. Таким образом, еслиautoInit == RefCountedAutoInitialize.noили вызывается для константного или неизменяемого объекта, тоrefCountedPayloadтакже будет квалифицироваться как безопасный и без исключений (но всё равно будет проверять на инициализацию).
- RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val);
-
Инициализирует
RefCountedзначениемval. Шаблонный параметрTдляRefCountedвыводится изval. Эта функция может использоваться для перемещения некопируемых значений в кучу. Она также отключает опциюautoInitдляRefCounted.- Параметры:
T valЗначение, подлежащее счёту ссылок
- Возвращает:
- Инициализированный
RefCounted, содержащийval.
- См. также:
- C++'s make_shared
- Примеры:
-
static struct File { string name; @disable this(this); // not copyable ~this() { name = null; } } auto file = File("name"); writeln(file.name); // "name" // file cannot be copied and has unique ownership static assert(!__traits(compiles, {auto file2 = file;})); // make the file refcounted to share ownership import std.algorithm.mutation : move; auto rcFile = refCounted(move(file)); writeln(rcFile.name); // "name" writeln(file.name); // null auto rcFile2 = rcFile; writeln(rcFile.refCountedStore.refCount); // 2 // file gets properly closed when last reference is dropped
- template Proxy(alias a)
-
Создаёт прокси для значения
a, которое будет перенаправлять все операции, отключая неявные преобразования. Алиасируемый элементaдолжен быть lvalue. Это полезно для создания нового типа на основе "базового" типа (хотя это не отношение подтип-супертип; новый тип никак не связан со старым типом по задумке).Новый тип поддерживает все операции, которые выполняет базовый тип, включая все операторы, такие как
+,--,<,[], и т.д.- Параметры:
a Значение, выступающее в роли прокси для всех операций. Оно должно быть lvalue.
- Примеры:
-
struct MyInt { private int value; mixin Proxy!value; this(int n){ value = n; } } MyInt n = 10; // Enable operations that original type has. ++n; writeln(n); // 11 writeln(n * 2); // 22 void func(int n) { } // Disable implicit conversions to original type. //int x = n; //func(n);
- Примеры:
- Проксируемое значение должно быть lvalue.
struct NewIntType { //Won't work; the literal '1' //is an rvalue, not an lvalue //mixin Proxy!1; //Okay, n is an lvalue int n; mixin Proxy!n; this(int n) { this.n = n; } } NewIntType nit = 0; nit++; writeln(nit); // 1 struct NewObjectType { Object obj; //Ok, obj is an lvalue mixin Proxy!obj; this (Object o) { obj = o; } } NewObjectType not = new Object(); assert(__traits(compiles, not.toHash()));
- Примеры:
- Существует одно исключение из того факта, что новый тип не связан со старым типом. Псевдочленные функции могут использоваться с новым типом; они будут перенаправлены на проксируемое значение.
import std.math; float f = 1.0; assert(!f.isInfinity); struct NewFloat { float _; mixin Proxy!_; this(float f) { _ = f; } } NewFloat nf = 1.0f; assert(!nf.isInfinity);
- struct Typedef(T, T init = T.init, string cookie = null);
-
Typedef позволяет создать уникальный тип, основанный на существующем типе. В отличие от возможности
alias, Typedef гарантирует, что два типа не будут считаться равными.- Параметры:
init Необязательное начальное значение для нового типа. cookie Необязательно, используется для создания нескольких уникальных типов, основанных на одном исходном типе T
- Примечание
- Если библиотечная функция не поддерживает тип Typedef, вы можете использовать шаблон
TypedefTypeдля извлечения типа, который оборачивает Typedef.
- Примеры:
-
alias MyInt = Typedef!int; MyInt foo = 10; foo++; writeln(foo); // 11
- Примеры:
- Значения пользовательской инициализации
alias MyIntInit = Typedef!(int, 42); static assert(is(TypedefType!MyIntInit == int)); static assert(MyIntInit() == 42);
- Примеры:
- Typedef создаёт новый тип
alias MyInt = Typedef!int; static void takeInt(int) {} static void takeMyInt(MyInt) {} int i; takeInt(i); // ok static assert(!__traits(compiles, takeMyInt(i))); MyInt myInt; static assert(!__traits(compiles, takeInt(myInt))); takeMyInt(myInt); // ok
- Примеры:
- Используйте необязательный аргумент
cookieдля создания различных типов на основе одного базового типаalias TypeInt1 = Typedef!int; alias TypeInt2 = Typedef!int; // The two Typedefs are the same type. static assert(is(TypeInt1 == TypeInt2)); alias MoneyEuros = Typedef!(float, float.init, "euros"); alias MoneyDollars = Typedef!(float, float.init, "dollars"); // The two Typedefs are _not_ the same type. static assert(!is(MoneyEuros == MoneyDollars));
- string toString(this T)();
void toString(this T, W)(ref W writer, ref scope const FormatSpec!char fmt)
Constraints: if (isOutputRange!(W, char)); -
Преобразование обернутого значения в удобочитаемую строку
- Примеры:
-
import std.conv : to; int i = 123; auto td = Typedef!int(i); writeln(i.to!string); // td.to!string
- template TypedefType(T)
-
Получение базового типа, который оборачивает
Typedef. ЕслиTне являетсяTypedef, он будет алиасирован наT.- Примеры:
-
import std.conv : to; alias MyInt = Typedef!int; static assert(is(TypedefType!MyInt == int)); /// Instantiating with a non-Typedef will return that type static assert(is(TypedefType!int == int)); string num = "5"; // extract the needed type MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); writeln(myInt); // 5 // cast to the underlying type to get the value that's being wrapped int x = cast(TypedefType!MyInt) myInt; alias MyIntInit = Typedef!(int, 42); static assert(is(TypedefType!MyIntInit == int)); static assert(MyIntInit() == 42);
- template scoped(T) if (is(T == class))
-
Выделяет объект
classнепосредственно внутри текущей области видимости, тем самым избегая накладных расходовnew. Данная функция небезопасна; ответственность за то, чтобы ссылка на объект не покидала область видимости, лежит на пользователе.Деструктор класса будет вызван при уничтожении результата
scoped().
Экземпляры scoped-классов могут быть вложены в родительскийclassилиstruct, как и экземпляры вложенных структур. scoped-члены должны быть типаtypeof(scoped!Class(args)), и инициализироваться вызовом scoped. См. пример ниже.- Примечание
- Перемещение экземпляра класса запрещено, даже если вы уверены, что на него нет ссылок. Поэтому перемещение scoped-объекта запрещено.
- Примеры:
-
class A { int x; this() {x = 0;} this(int i){x = i;} ~this() {} } // Standard usage, constructing A on the stack auto a1 = scoped!A(); a1.x = 42; // Result of `scoped` call implicitly converts to a class reference A aRef = a1; writeln(aRef.x); // 42 // Scoped destruction { auto a2 = scoped!A(1); writeln(a2.x); // 1 aRef = a2; // a2 is destroyed here, calling A's destructor } // aRef is now an invalid reference // Here the temporary scoped A is immediately destroyed. // This means the reference is then invalid. version (Bug) { // Wrong, should use `auto` A invalid = scoped!A(); } // Restrictions version (Bug) { import std.algorithm.mutation : move; auto invalid = a1.move; // illegal, scoped objects can't be moved } static assert(!is(typeof({ auto e1 = a1; // illegal, scoped objects can't be copied assert([a1][0].x == 42); // ditto }))); static assert(!is(typeof({ alias ScopedObject = typeof(a1); auto e2 = ScopedObject(); // illegal, must be built via scoped!A auto e3 = ScopedObject(1); // ditto }))); // Use with alias alias makeScopedA = scoped!A; auto a3 = makeScopedA(); auto a4 = makeScopedA(1); // Use as member variable struct B { typeof(scoped!A()) a; // note the trailing parentheses this(int i) { // construct member a = scoped!A(i); } } // Stack-allocate auto b1 = B(5); aRef = b1.a; writeln(aRef.x); // 5 destroy(b1); // calls A's destructor for b1.a // aRef is now an invalid reference // Heap-allocate auto b2 = new B(6); writeln(b2.a.x); // 6 destroy(*b2); // calls A's destructor for b2.a
- @system auto scoped(Args...)(auto ref Args args);
-
Возвращает scoped-объект.
- Параметры:
Args argsАргументы, передаваемые конструктору T
- template Flag(string name)
-
Определяет простой, самодокументируемый флаг «да/нет». Это упрощает API-интерфейсы для определения функций, принимающих флаги, без прибегания к
bool, что делает вызовы нечитаемыми, и без необходимости отдельно определять перечисление. ИспользованиеFlag!"Name"вместоboolделает смысл флага видимым в вызовах. Каждый флаг «да/нет» имеет свой собственный тип, что делает путаницу и ошибки невозможными.- Пример
- Код, вызывающий
getLine(обычно расположенный далеко от его определения), не может быть понят без просмотра документации, даже пользователями, знакомыми с API:
string getLine(bool keepTerminator) { ... if (keepTerminator) ... ... } ... auto line = getLine(false);Предполагая обратный смысл (т.е. «ignoreTerminator») и вставив неправильный код, компиляция и выполнение приведут к ошибочным результатам. После замены булевого параметра на экземплярFlag, код, вызывающийgetLine, легко читаем и понятен, даже пользователям, не знакомым с API:string getLine(Flag!"keepTerminator" keepTerminator) { ... if (keepTerminator) ... ... } ... auto line = getLine(Yes.keepTerminator);СтруктурыYesиNoпредоставляются как сокращения дляFlag!"Name".yesиFlag!"Name".noи предпочтительны для краткости и удобочитаемости. Эти удобные структуры обычно делают ненужным и нецелесообразным создание псевдонима дляFlagв качестве способа избежания ввода полного типа при указании утвердительных или отрицательных вариантов. Передача категориальных данных посредством неструктурированныхboolпараметров классифицируется Стивом МакКоннелом в книге «Code Complete» как «связь простых данных», наряду с тремя другими видами связи. Автор, ссылаясь на несколько исследований, утверждает, что связь оказывает негативное влияние на качество кода.Flagпредлагает простой способ структурирования для передачи флагов «да/нет» в API.- Примеры:
-
Flag!"abc" flag; writeln(flag); // Flag!"abc".no writeln(flag); // No.abc assert(!flag); if (flag) assert(0);
- Примеры:
-
auto flag = Yes.abc; assert(flag); writeln(flag); // Yes.abc if (!flag) assert(0); if (flag) {} else assert(0);
- перечисление Flag: bool;
-
- no
-
При создании значения типа
Flag!"Name", используйтеFlag!"Name".noдля отрицательного варианта. При использовании значения типаFlag!"Name", сравнивайте его сFlag!"Name".noили простоfalseили0. - yes
-
При создании значения типа
Flag!"Name", используйтеFlag!"Name".yesдля утвердительного варианта. При использовании значения типаFlag!"Name", сравнивайте его сFlag!"Name".yes.
- структура Yes;
структура No; -
Удобные имена, которые позволяют использовать, например,
Yes.encryptionвместоFlag!"encryption".yesиNo.encryptionвместоFlag!"encryption".no.- Примеры:
-
Flag!"abc" flag; writeln(flag); // Flag!"abc".no writeln(flag); // No.abc assert(!flag); if (flag) assert(0);
- Примеры:
-
auto flag = Yes.abc; assert(flag); writeln(flag); // Yes.abc if (!flag) assert(0); if (flag) {} else assert(0);
- шаблон isBitFlagEnum(E)
-
Определяет, является ли перечисление целочисленного типа и содержит только значения «флага» (т.е. значения с количеством битов ровно 1). Кроме того, разрешено нулевое значение для совместимости с перечислениями, включающими значение «None».
- Примеры:
-
enum A { None, A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3, } static assert(isBitFlagEnum!A);
- Примеры:
- Тестирование перечисления с значениями по умолчанию (последовательными)
enum B { A, B, C, D // D == 3 } static assert(!isBitFlagEnum!B);
- Примеры:
- Тестирование перечисления с нецелочисленными значениями
enum C: double { A = 1 << 0, B = 1 << 1 } static assert(!isBitFlagEnum!C);
- структура BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) if (unsafe || isBitFlagEnum!E);
-
Типобезопасная структура для хранения комбинаций значений перечисления.
Этот шаблон определяет простую структуру для представления комбинаций значений перечисления по битовому ИЛИ. Он может использоваться, если все значения перечисления являются целочисленными константами с количеством битов не более 1, или если параметр
unsafeявно установлен в Yes. Это гораздо безопаснее, чем использование самого перечисления для хранения комбинации ИЛИ, что может привести к неожиданным результатам, например:enum E { A = 1 << 0, B = 1 << 1 } E e = E.A | E.B; // will throw SwitchError final switch (e) { case E.A: return; case E.B: return; }- Примеры:
- Установка значений оператором | и проверка оператором &
enum Enum { A = 1 << 0, } // A default constructed BitFlags has no value set immutable BitFlags!Enum flags_empty; assert(!flags_empty.A); // Value can be set with the | operator immutable flags_A = flags_empty | Enum.A; // and tested using property access assert(flags_A.A); // or the & operator assert(flags_A & Enum.A); // which commutes. assert(Enum.A & flags_A);
- Примеры:
- Структура BitFlags по умолчанию не имеет установленных значений
enum Enum { None, A = 1 << 0, B = 1 << 1, C = 1 << 2 } immutable BitFlags!Enum flags_empty; assert(!(flags_empty & (Enum.A | Enum.B | Enum.C))); assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));
- Примеры:
- Бинарные операции: вычитание и пересечение флагов
enum Enum { A = 1 << 0, B = 1 << 1, C = 1 << 2, } immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); // Use the ~ operator for subtracting flags immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); assert(!flags_B.A && flags_B.B && !flags_B.C); // use & between BitFlags for intersection writeln(flags_B); // (flags_BC & flags_AB)
- Примеры:
- Все бинарные операторы работают и в их присваивающей форме
enum Enum { A = 1 << 0, B = 1 << 1, } BitFlags!Enum flags_empty, temp, flags_AB; flags_AB = Enum.A | Enum.B; temp |= flags_AB; writeln(temp); // (flags_empty | flags_AB) temp = flags_empty; temp |= Enum.B; writeln(temp); // (flags_empty | Enum.B) temp = flags_empty; temp &= flags_AB; writeln(temp); // (flags_empty & flags_AB) temp = flags_empty; temp &= Enum.A; writeln(temp); // (flags_empty & Enum.A)
- Примеры:
- Преобразование в bool и int
enum Enum { A = 1 << 0, B = 1 << 1, } BitFlags!Enum flags; // BitFlags with no value set evaluate to false assert(!flags); // BitFlags with at least one value set evaluate to true flags |= Enum.A; assert(flags); // This can be useful to check intersection between BitFlags BitFlags!Enum flags_AB = Enum.A | Enum.B; assert(flags & flags_AB); assert(flags & Enum.A); // You can of course get you raw value out of flags auto value = cast(int) flags; writeln(value); // Enum.A
- Примеры:
- Необходимо указать параметр
unsafeдля перечислений с пользовательскими значениямиenum UnsafeEnum { A = 1, B = 2, C = 4, BC = B|C } static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; })); BitFlags!(UnsafeEnum, Yes.unsafe) flags; // property access tests for exact match of unsafe enums flags.B = true; assert(!flags.BC); // only B flags.C = true; assert(flags.BC); // both B and C flags.B = false; assert(!flags.BC); // only C // property access sets all bits of unsafe enum group flags = flags.init; flags.BC = true; assert(!flags.A && flags.B && flags.C); flags.A = true; flags.BC = false; assert(flags.A && !flags.B && !flags.C);
- шаблон ReplaceType(From, To, T...)
-
Заменяет все вхождения
FromнаTo, в одном или нескольких типахT. Например,ReplaceType!(int, uint, Tuple!(int, float)[string])даетTuple!(uint, float)[string]. Типы, в которых выполняется замена, могут быть произвольно сложными, включая квалификаторы, встроенные конструкторы типов (указатели, массивы, ассоциативные массивы, функции и делегаты), и экземпляры шаблонов; замена происходит транзитивно через определение типа. Однако, типы членов вstructилиclassне заменяются, так как нет способов выразить типы, полученные после замены.Это продвинутая манипуляция типами, необходимая, например, для замены типа-заполнителя
Thisвstd.variant.Algebraic.- Возвращает:
-
ReplaceTypeсвязывает себя с результатом замены.
- Примеры:
-
static assert( is(ReplaceType!(int, string, int[]) == string[]) && is(ReplaceType!(int, string, int[int]) == string[string]) && is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && is(ReplaceType!(int, string, Tuple!(int[], float)) == Tuple!(string[], float)) );
- шаблон ReplaceTypeUnless(alias pred, From, To, T...)
-
Подобно
ReplaceType, но не выполняет замену в типах, для которыхpredоценивается какtrue.- Примеры:
-
import std.traits : isArray; static assert( is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) == Tuple!(string, int[])) );
- структура Ternary;
-
Тройственный тип с тремя значениями истинности:
-
Ternary.yesдляtrue -
Ternary.noдляfalse -
Ternary.unknownкак неизвестное состояние
Также известен как троичный, трёхвалентный или трилевый.- См. также:
- Трёхзначная логика в Википедии
- Примеры:
-
Ternary a; writeln(a); // Ternary.unknown writeln(~Ternary.yes); // Ternary.no writeln(~Ternary.no); // Ternary.yes writeln(~Ternary.unknown); // Ternary.unknown
- перечисление Ternary no;
перечисление Ternary yes;
перечисление Ternary unknown; -
Возможные состояния
Ternary - чистая nothrow @nogc @safe this(bool b);
чистая nothrow @nogc @safe void opAssign(bool b); -
Создание и присвоение из
bool, получаяnoдляfalseиyesдляtrue. - чистая nothrow @nogc @safe this(const Ternary b);
-
Создание трёхвалентного значения из другого трёхвалентного значения
- Ternary opUnary(string s)()
Ограничения: if (s == "~");
Ternary opBinary(string s)(Ternary rhs)
Ограничения: if (s == "|");
Ternary opBinary(string s)(Ternary rhs)
Ограничения: if (s == "&");
Ternary opBinary(string s)(Ternary rhs)
Ограничения: if (s == "^");
Ternary opBinary(string s)(bool rhs)
Ограничения: if (s == "|" || s == "&" || s == "^"); -
Таблица истинности для логических операций ab˜aa | ba & ba ^ bnonoyesnonononoyesyesnoyesnounknownunknownnounknownyesnonoyesnoyesyesyesyesyesnoyesunknownyesunknownunknownunknownnounknownunknownnounknownunknownyesyesunknownunknownunknownunknownunknownunknownunknown
-
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_typecons.html