std.conv

Переместиться к: castFrom · ConvException · ConvOverflowException · dtext · emplace · hexString · octal · parse · roundTo · signed · text · to · toChars · unsigned · wtext

Универсальный магазин для преобразования значений из одного типа в другой.
Лицензия:
Boost License 1.0.
Авторы:
Walter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara

Исходный код: std/conv.d

class ConvException: object.Exception;
Исключение, бросаемое при ошибках преобразования.
class ConvOverflowException: std.conv.ConvException;
Исключение, бросаемое при ошибках переполнения во время преобразования.
template to(T)
Шаблон to преобразует значение из одного типа в другой. Исходный тип выводится, а целевой тип должен быть определен, например выражение to!int(42.0) преобразует число 42 из double в int. Преобразование является "безопасным", то есть, при нём происходит проверка на наличие переполнения; to!int(4.2e10) должно бросить исключение ConvOverflowException. Проверки переполнения включаются только когда необходимо, например, to!double(42) не выполняет каких-либо проверок, поскольку любой int помещается в double.
Преобразования из строковых в числовые типы отличаются от эквивалентов из C atoi() и atol() проверкой на переполнение и тем, что не допускают пробелы.
Для преобразования строк в знаковые типы, общепризнанная грамматика такая:
Integer: Sign UnsignedInteger
UnsignedInteger
Sign:
    +
    -
Для преобразования строк в беззнаковые типы, общепризнанная грамматика такая:
UnsignedInteger:
    DecimalDigit
    DecimalDigit UnsignedInteger
Примеры:
Преобразование значений в свой собственный тип (полезно по большей части для обобщённого кода), просто возвращает свой аргумент.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c – это double со значением 3.14
Примеры:
Преобразование между числовыми типами – безопасный способ использовать cast.
Преобразования из типов с плавающей точкой в целые типы допускают потерю точности (дробная часть чисел с плавающей точкой). Преобразование усекает в сторону нуля, точно так же усекал бы cast. (Чтобы округлять значения с плавающей точкой, преобразуя их в целые, используйте roundTo.)
import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
Примеры:
Заметьте, что D при преобразовании строк в числовые типы не обрабатывает шестнадцатеричные и двоичные литералы. Ни префиксы, которые указывают базу, ни горизонтальные подчеркивания, используемые для разделения групп цифр, не распознаются. Это также относится к суффиксам, которые указывают на тип.
Чтобы обойти эту проблему, вы можете определить основание для преобразований, связанных с числами.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Примеры:
Преобразования из целых типов в типы с плавающей точкой всегда удаются, но могут привести к потере точности. Самые большие целые, представимые в формате с плавающей точкой – 2^24-1 для float, 2^53-1 для double, и 2^64-1 для real (когда real – 80-битный, например, в машинах Intel).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Примеры:
Преобразование массива в массив другого типа работает через преобразование каждого элемента по очереди. Ассоциативные массивы, могут быть преобразованы в ассоциативные массивы, пока ключи и значения могут быть преобразованы в свою очередь.
import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Примеры:
Преобразования действуют транзитивно, а это означает, что они работают с массивами и ассоциативными массивами любой сложности.
Это преобразование работает, поскольку to!short относится к int, to!wstring относится к string, to!string относится к double, и to!(double[]) относится к int[]. Преобразование может бросить исключение, поскольку to!short может потерпеть неудачу при контроле на переполнение.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Примеры:
Преобразования объект-объект динамического приведения типа бросают исключение, если источник не-null, а цель – null.
import std.exception : assertThrown;
// Тестирование преобразований объектов
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Примеры:
Поддерживаются строковые преобразования из любых типов.
  • Преобразование строки в строку работает для любых двух типов строки, с любой шириной символа (char, wchar, dchar) и с любой комбинацией квалификаторов (изменяемые, const, или immutable).
  • Преобразования массивов (кроме строк) в строки. Каждый элемент преобразуется вызовом to!T.
  • Преобразование ассоциативного массива в строку. Каждый элемент печатается вызовом to!T.
  • Преобразование объекта в строку вызывает toString у объекта или возвращает "null", если объект – null.
  • Преобразование структуры в строку вызывает toString у структуры, если этот метод определён.
  • Для структур, в которых не определён toString, преобразование в строку формирует список полей.
  • Типы перечислений преобразуются в строки как их символические имена.
  • Значения типа Boolean печатаются как "true" или "false".
  • char, wchar, dchar в строковый тип.
  • Беззнаковые или знаковые целые в строки.
    [специальный случай]
    Преобразования целых значений в строки по основанию radix. Основание должно быть величиной от 2 до 36. Значения рассматриваются как знаковые, только если основание равно 10. Символы от A до Z используются для представления значений от 10 до 36, и их регистр определяется параметром letterCase.
  • Все типы с плавающей точкой во все типы строк.
  • Преобразование указателя в строку печатает указатель как величину size_t. Если указатель – это char*, он рассматривается как строка в C-стиле. В таком случае, эта функция будет @system.
// Преобразование, представляющее динамический/статический массив в виде строки
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Преобразование, представляющее ассоциативный массив в виде строки
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// преобразование char* в string
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Преобразование массива типа void в строку
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");
template roundTo(Target)
Преобразование округления из чисел с плавающей точкой в целые.
Преобразования округления не работают с не-целыми целевыми типами.
Примеры:
assert(roundTo!int(3.14) == 3);
assert(roundTo!int(3.49) == 3);
assert(roundTo!int(3.5) == 4);
assert(roundTo!int(3.999) == 4);
assert(roundTo!int(-3.14) == -3);
assert(roundTo!int(-3.49) == -3);
assert(roundTo!int(-3.5) == -4);
assert(roundTo!int(-3.999) == -4);
assert(roundTo!(const int)(to!(const double)(-3.999)) == -4);

Переместиться к: 2 · 3 · 4 · 5 · 6 · 7 · 8

Target parse(Target, Source)(ref Source s)
if (isInputRange!Source && isSomeChar!(ElementType!Source) && is(Unqual!Target == bool));
Семейство функций parse работает совсем как семейство to, за исключением:
  1. Оно работает только с символьными диапазонами на входе.
  2. Оно принимает входные данные по ссылке. (Это означает, что rvalues – как например, литералы строк – не принимаются: используйте в таком случае to.)
  3. Оно продвигает вход в позицию после преобразования.
  4. Оно не бросает исключений, если не получилось преобразовать весь вход.
Эта перегрузка преобразует символьный входной диапазон в bool.
Параметры:
Target тип, в который надо преобразовать
Source s lvalue – входной диапазон
Возвращает:
bool
Исключения:
ConvException, если диапазон не представляет bool.

Замечание: Все преобразования символьных входных диапазонов, использующие to , перенаправляются к parse и не требуют lvalues.

Примеры:
auto s = "true";
bool b = parse!bool(s);
assert(b);
Target parse(Target, Source)(ref Source s)
if (isSomeChar!(ElementType!Source) && isIntegral!Target && !is(Target == enum));

Target parse(Target, Source)(ref Source s, uint radix)
if (isSomeChar!(ElementType!Source) && isIntegral!Target && !is(Target == enum));
Выполняет грамматический разбор символьного входного диапазона в целое значение.
Параметры:
Target целый тип, в который надо преобразовать
Source s lvalue – входной диапазон
Возвращает:
Число типа Target
Исключения:
ConvException, если во время преобразования произошло переполнение, или если никакой входной символ не был значимо преобразован.
Примеры:
string s = "123";
auto a = parse!int(s);
assert(a == 123);

// parse принимает только lvalues
static assert(!__traits(compiles, parse!int("123")));
Примеры:
import std.string : munch;
string test = "123 \t  76.14";
auto a = parse!uint(test);
assert(a == 123);
assert(test == " \t  76.14"); // разобрать неровную строку 
munch(test, " \t\n\r"); // пропустить ws
assert(test == "76.14");
auto b = parse!double(test);
assert(b == 76.14);
assert(test == "");
Target parse(Target, Source)(ref Source s)
if (isSomeString!Source && !is(Source == enum) && is(Target == enum));
Принимает строку, представляющую тип enum и возвращает этот тип.
Параметры:
Target Тип enum, в который надо преобразовать
Source s lvalue – входной диапазон для разбора
Возвращает:
Перечисление типа Target
Исключения:
ConvException, если тип Target не представлен строкой s.
Примеры:
enum EnumType : bool { a = true, b = false, c = a }

auto str = "a";
assert(parse!EnumType(str) == EnumType.a);
Target parse(Target, Source)(ref Source p)
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && isFloatingPoint!Target && !is(Target == enum));
Выполняет грамматический разбор символьного диапазона в число с плавающей точкой.
Параметры:
Target тип числа с плавающей точкой, в который надо преобразовать
Source p lvalue – входной диапазон для разбора
Возвращает:
число с плавающей точкой типа Target
Исключения:
ConvException, если p пуст, если число не разобрано, или если случилось переполнение.
Примеры:
import std.math : approxEqual;
auto str = "123.456";

assert(parse!double(str).approxEqual(123.456));
Target parse(Target, Source)(ref Source s)
if (isSomeString!Source && !is(Source == enum) && staticIndexOf!(Unqual!Target, dchar, Unqual!(ElementEncodingType!Source)) >= 0);

Target parse(Target, Source)(ref Source s)
if (!isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source) && isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum));
Грамматический разбор одного символа из диапазона, возвращает первый элемент и вызывает popFront.
Параметры:
Target тип, в который надо преобразовать
Source s lvalue – входной диапазон
Возвращает:
Символьный тип Target
Исключения:
ConvException, если диапазон пуст.
Примеры:
auto s = "Hello, World!";
char first = parse!char(s);
assert(first == 'H');
assert(s == "ello, World!");
Target parse(Target, Source)(ref Source s)
if (isInputRange!Source && isSomeChar!(ElementType!Source) && is(Unqual!Target == typeof(null)));
Выполняет грамматический разбор символьного диапазона в typeof(null), возвращая null, если диапазон состоит из букв "null". Эта функция нечувствительна к регистру.
Параметры:
Target тип, в который надо преобразовать
Source s lvalue – входной диапазон
Возвращает:
null
Исключения:
ConvException, если диапазон не представляет null.
Примеры:
import std.exception : assertThrown;

alias NullType = typeof(null);
auto s1 = "null";
assert(parse!NullType(s1) is null);
assert(s1 == "");

auto s2 = "NUll"d;
assert(parse!NullType(s2) is null);
assert(s2 == "");

auto m = "maybe";
assertThrown!ConvException(parse!NullType(m));
assert(m == "maybe");  // m не должна измениться в случае неудачи

auto s = "NULL";
assert(parse!(const NullType)(s) is null);
Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',')
if (isExactSomeString!Source && isDynamicArray!Target && !is(Target == enum));

Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',')
if (isExactSomeString!Source && isStaticArray!Target && !is(Target == enum));
Выполняет грамматический разбор в массив из строки с передаваемыми левой скобкой (по-умолчанию '['), правой скобкой (по-умолчанию ']'), и разделителя элементов (по умолчанию ',').
Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar keyval = ':', dchar comma = ',')
if (isExactSomeString!Source && isAssociativeArray!Target && !is(Target == enum));
Выполняет грамматический разбор в ассоциативный массив из строки с передаваемыми левой скобкой (по-умолчанию '['), правой скобкой (по-умолчанию ']'), разделителя ключ-значение (по-умолчанию ':'), и разделителя элементов (по умолчанию ',').
string text(T...)(T args)
if (T.length > 0);

wstring wtext(T...)(T args)
if (T.length > 0);

dstring dtext(T...)(T args)
if (T.length > 0);
Удобные функции для преобразования одного или более аргументов любого типа в текст (три ширины символа).
Примеры:
assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c);
assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);
template octal(string num) if (isOctalLiteral(num))

template octal(alias decimalInteger) if (isIntegral!(typeof(decimalInteger)))
Объект octal предоставляет средства объявлять числа с основанием 8. Используйте octal!177 или octal!"177" для представления 127 в восьмиричном виде (тоже, что 0177 в C).
Правила для строк обычные для литералов: если её можно преобразовать в int,, то это – int. В противном случае, это long. Но, если пользователь специально требует long с помощью суффикса L, всегда даётся long. Беззнаковый тип даётся тогда и только тогда, когда есть требование через суффикс U или u. Восьмиричные числа, созданные из целых, сохраняют тип переданного целого.
Смотрите также:
parse для синтаксического разбора строк, представляющих восьмеричные числа, во время выполнения.
Примеры:
// тоже, что 0177
auto x = octal!177;
// octal действует во время компиляции
enum y = octal!160;
// Создание беззнакового восьмеричного числа
auto z = octal!"1_000_000u";

Переместиться к: 2 · 3 · 4

pure nothrow @safe T* emplace(T)(T* chunk);
Данный указатель на неинициализированную память chunk (но уже типизированный в T), создает объект типа T, не являющегося классом, по этому адресу. Если T – это класс, инициализирует ссылку в null.
Возвращает:
Указатель на вновь созданный объект (что тоже самое, что и chunk).
Примеры:
static struct S
{
    int i = 42;
}
S[2] s2 = void;
emplace(&s2);
assert(s2[0].i == 42 && s2[1].i == 42);
Примеры:
interface I {}
class K : I {}

K k = void;
emplace(&k);
assert(k is null);

I i = void;
emplace(&i);
assert(i is null);
T* emplace(T, Args...)(T* chunk, auto ref Args args)
if (is(T == struct) || Args.length == 1);
Даётся указатель на неинициализированную память chunk (но уже типизированный как тип T, не являющийся классом), создает объект типа T по этому адресу из аргументов args. Если T – это класс, инициализирует ссылку класса на args[0].
Эта функция может быть @trusted, если соответсвующий конструктор T является @safe.
Возвращает:
Указатель на вновь созданный объект (что тоже самое, что и chunk).
Примеры:
int a;
int b = 42;
assert(*emplace!int(&a, b) == 42);
T emplace(T, Args...)(void[] chunk, auto ref Args args)
if (is(T == class));
Даётся область сырой памяти chunk, создается объект типа class type T являющийся классом, по этому адресу. В конструктор передаются аргументы Args.
Если T является внутренним классом, чье поле outer может использоваться для доступа к экземпляру включающего класса, то Args не должно быть пусто, и первым его членом должен быть правильный инциализатор для этого поля outer. Правильная инициализация этого поля имеет важное значение для доступа к членам внешнего класса внутри методов T.

Предусловия: chunk должен быть по крайней мере таким же большим как требуется T, и должен иметь выравнивание, кратное выравниванию T. (Размер экземпляра класса можно получить с использованием _traits(classInstanceSize, T)).

Замечание: Эта функция может быть @trusted, если соответсвующий конструктор T является @safe.

Возвращает:
Вновь созданный объект.
Примеры:
static class C
{
    int i;
    this(int i){this.i = i;}
}
auto buf = new void[__traits(classInstanceSize, C)];
auto c = emplace!C(buf, 5);
assert(c.i == 5);
T* emplace(T, Args...)(void[] chunk, auto ref Args args)
if (!is(T == class));
Даётся область сырой памяти chunk, создает объект типа T, не являющийся классом, по этому адресу. Конструктору передаются аргументы args, если имеются.

Предусловия: chunk должен быть по крайней мере таким же большим как требуется T, и должен иметь выравнивание, кратное выравниванию T.

Замечание: Эта функция может быть @trusted, если соответсвующий конструктор T является @safe.

Возвращает:
Указатель на вновь созданный объект.
Примеры:
struct S
{
    int a, b;
}
auto buf = new void[S.sizeof];
S s;
s.a = 42;
s.b = 43;
auto s1 = emplace!S(buf, s);
assert(s1.a == 42 && s1.b == 43);
auto unsigned(T)(T x)
if (isIntegral!T);
Возвращает соответствующее беззнаковое значение для x (например, если x имеет тип int, то будет возвращён cast(uint) x). Преимущество по сравнению с cast в том, что вам не нужно переписывать cast, если впоследствии тип x изменится (например, из int в long).
Заметьте, что результат - всегда изменяемый, даже если бы исходный тип был const или immutable. Для того, чтобы сохранить константность, используйте std.traits.Unsigned.
Примеры:
immutable int s = 42;
auto u1 = unsigned(s); //нет квалификатора
static assert(is(typeof(u1) == uint));
Unsigned!(typeof(s)) u2 = unsigned(s); //та же квалификация
static assert(is(typeof(u2) == immutable uint));
immutable u3 = unsigned(s); //явный квалификатор
auto signed(T)(T x)
if (isIntegral!T);
Возвращает соответствующее знаковое значение для x (например, если x имеет тип uint, то будет возвращён cast(int) x). Преимущество по сравнению с cast в том, что вам не нужно переписывать cast, если впоследствии тип x изменится (например, из uint в ulong).
Заметьте, что результат - всегда изменяемый, даже если бы исходный тип был const или immutable. Для того, чтобы сохранить константность, используйте std.traits.Signed.
Примеры:
immutable uint u = 42;
auto s1 = signed(u); //not qualified
static assert(is(typeof(s1) == int));
Signed!(typeof(u)) s2 = signed(u); //same qualification
static assert(is(typeof(s2) == immutable int));
immutable s3 = signed(u); //explicitly qualified

Переместиться к: to

template castFrom(From)
Обёртка поверх встроенного оператора cast, которая позволяет ограничить приведение по типу исходного значения.
Общая проблема с использованием сырого cast состоит в том, что он может молча продолжить компиляцию, даже если тип значения изменился во время рефакторинга, и нарушилось первоначальное предположение о cast.
Параметры:
From Тип, из которого приводится. Программист должен гарантировать, что он легален для выполнения cast.
ref @system auto to(To, T)(auto ref T value);
Параметры:
To Тип, к которому приводится.
T value Приводимое значение. Он должен быть типа From, в противном случае выдаётся ошибка времени компиляции.
Возвращает:
значение после приведения, возвращённое ссылкой, если возможно.
Примеры:
// Обычный cast, который проверяется на легальность программистом:
{
    long x;
    auto y = cast(int) x;
}

// Однако, это всё ещё компилируется, если 'x' измениться на указатель:
{
    long* x;
    auto y = cast(int) x;
}

// castFrom предоставляет более надёжную альтернативу для приведения:
{
    long x;
    auto y = castFrom!long.to!int(x);
}

// Изменение типа 'x' теперь выдаст ошибку компилятора,
// позволяя ловить плохие приведения до того, как будет слишком поздно:
{
    long* x;
    static assert (
        !__traits(compiles, castFrom!long.to!int(x))
    );

    // если cast всё ещё нужен, его надо изменить на:
    auto y = castFrom!(long*).to!int(x);
}
template hexString(string hexData) if (hexData.isHexLiteral)

template hexString(wstring hexData) if (hexData.isHexLiteral)

template hexString(dstring hexData) if (hexData.isHexLiteral)
Преобразует шестнадцатеричный литерал в строку во время компиляции.
Принимает строку, составленную из шестнадцатеричных цифр, и возвращает соответствующую строку, преобразуя каждую пару цифр в символ. Входная строка может также включать пробельные символы, которые могут быть использованы, чтобы удерживать строку с литералами в удобочитаемом виде в исходном коде.
Предполагается заменить этой функцией шестнадцатеричные строки литералов, начинающиеся с 'x', которые могут быть удалены для упрощения основного языка.
Параметры:
hexData преобразуемая строка.
Возвращает:
string, wstring или dstring, в соответсвии с типом hexData.
Примеры:
// преобразование во время компиляции
auto string1 = hexString!"304A314B";
assert(string1 == "0J1K");
auto string2 = hexString!"304A314B"w;
assert(string2 == "0J1K"w);
auto string3 = hexString!"304A314B"d;
assert(string3 == "0J1K"d);
pure nothrow @nogc @safe auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value)
if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) && (is(Unqual!T == uint) || is(Unqual!T == ulong) || radix == 10 && (is(Unqual!T == int) || is(Unqual!T == long))));
Преобразование целого в диапазон символов. Предназначен быть легким и быстрым.
Параметры:
radix 2, 8, 10, 16
Char тип символов для вывода
letterCase lower (нижний) для deadbeef, upper (верхний) для DEADBEEF
T value преобразуемое целое. Может быть uint или ulong. Если основание равно 10, может также быть int или long.
Возвращает:
Диапазон с произвольным доступом с поддержкой срезов и всего