std.conv
値をある型から他の型へと変換する何でも屋です。Authors:
Walter Bright, Andrei Alexandrescu
- 変換の際にエラーが起きたときに投げられる例外です。
- 変換時にオーバーフローが起きたときの例外です。
- to 系統の関数は、
Source 型の値を Target 型に変換します。
Sourceの型は与えられた引数から推論されますが、Targetは明示する必要があります。
例えば to!(int)(42.0) は double 型の 42 から
int への変換を行います。変換は "安全" です。
つまり、オーバーフローのチェックが行われます。 to!(int)(4.2e10)
は ConvOverflowError 例外を投げます。オーバーフローチェックは必要な時にのみ挿入されます。
例えば、to!(double)(42)
の場合 int は確実に double に収まるので、余計なチェックは発生しません。
値を同じ型に変換する場合 (ジェネリックなコードを使ったときに起こりえます) は、 単に引数をそのまま返します。
Example:
int a = 42; auto b = to!(int)(a); // b は int 型の 42 auto c = to!(double)(3.14); // c は double 型の 3.14
数値型の間の変換は、安全にキャストする手段として使うことが出来ます。 浮動小数点型から整数型への変換は常に精度のロスを伴います (小数部分が捨てられるので)。 to による変換では、キャストの場合と同様にゼロ方向へと切り捨てが行われます。 (丸め処理を行って欲しい場合は、 roundTo を使用します。)
Examples:
int a = 420; auto b = to!(long)(a); // long b = a; と同じ auto c = to!(byte)(a / 10); // 問題なし。c = 42 auto d = to!(byte)(a); // ConvOverflowError 例外 double e = 4.2e6; auto f = to!(int)(e); // f == 4200000 e = -3.14; auto g = to!(uint)(e); // エラー。アンダーフロー e = 3.14; auto h = to!(uint)(e); // h = 3 e = 3.99; h = to!(uint)(a); // h = 3 e = -3.99; f = to!(int)(a); // f = -3
整数型から浮動小数点型への変換は常に成功しますが、 やはり精度が落ちる可能性があります。 浮動小数点形式で1刻みで表現可能な最大の整数は、 float なら 2^24-1、double なら 2^53-1、real なら 2^64-1 です (例えばIntelのマシンのように real が 80-bit の場合)。
Example:
int a = 16_777_215; // 2^24 - 1, 全桁をfloatで表現可能な最大の整数 assert(to!(int)(to!(float)(a)) == a); assert(to!(int)(to!(float)(-a)) == -a); a += 2; assert(to!(int)(to!(float)(a)) == a); // fails!
文字列から整数型への変換では、 atoi() や atol() 関数と違い、 空白文字やオーバーフローを禁止しています。
符号付き型への変換に関しては、認識される文字列の形式は以下の通りです:Integer: Sign UnsignedInteger UnsignedInteger Sign: + -符号なし型への変換に関しては以下の通りです:UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger
配列から他の配列への変換は、要素を1つずつ変換する動作になります。 連想配列も、keyとvalueが変換可能であれば、 それぞれ変換した新しい連想配列を作ることが可能です。
Example:
int[] a = ([1, 2, 3]).dup; 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);
この変換は推移的です、つまり 配列や連想配列を何重に重ねても動作します:
int[string][double[int[]]] a; ... auto b = to!(short[wstring][string[double[]]])(a);
この変換は、int に to!(short) が適用され、 string に to!(wstring) が適用され、 double に to!(string) が適用され、 int[] に to!(double[]) が適用され、 int から to!(short) の変換部分でオーバーフロー例外が発生することがあります。
- 浮動小数点数から整数への丸め変換です。
Example:
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);
変換先が整数型でない場合は動作しません。
- parse 関数は
to とよく似た動作をします。違いは (1) 入力として文字列のみを受け取る
(2) 文字列を参照で受け取り、
変換で読み込んだ分先に進める (3) 全体を変換できなかったとしても例外を投げない、の3点です。
オーバーフローが起きたり、
1文字も読み取れなかった場合などは
依然として例外が発生します。
Example:
string test = "123 \t 76.14"; auto a = parse!(uint)(test); assert(a == 123); assert(test == " \t 76.14"); // パースした残り munch(test, " \t\n\r"); // ホワイトスペースをスキップ assert(test == "76.14"); auto b = parse!(double)(test); assert(b == 76.14); assert(test == "");
- 文字列を返値型に変換します。
to!(T) によって置き換えられたため、これらの関数は非推奨となっています。
