std.algorithm.comparision.clamp
を使う
import std.algorithm.comparison : clamp;
void compress(ref int quality)
{
quality = clamp(quality, 0, 100);
}
void main()
{
int quality = 110;
compress(quality);
assert(quality == 100);
}
std.math
に数学定数が定義されている
import std.math;
import std.stdio;
void main()
{
writeln(2.0 * PI); // real型
writeln(2.0 * cast(double) PI); // double型
}
std.string
に便利関数が定義されている
import std.string : endsWith, startsWith;
void main()
{
string path = "test.png";
assert(path.endsWith("png"));
assert(!path.endsWith("jpg"));
string url = "https://dlang.org";
assert(url.startsWith("https://"));
}
- 組み込み連想配列に対する操作
in
でキーの有無チェックが可能
import std.stdio;
void main()
{
int[string] table = ["one": 1, "two": 2];
auto p = "one" in table;
if (p !is null)
writeln("oneというキーを持つ要素が存在");
}
- より汎用的な
with文
を使う
enum ImageFormat { BMP, PNG, JPEG, DDS };
// 返り値の型手抜き
int decode(ImageFormat format)
{
switch (format) with (ImageFormat)
{
case BMP: return 0;
case PNG: return 1;
case JPEG: return 2;
case DDS: return 3;
default: return -1;
}
}
static assert(decode(ImageFormat.PNG) == 1);
std.algorithm.mutation.remove
を使う
import std.algorithm.mutation : remove;
import std.array : array;
import std.stdio : writeln;
void main()
{
int[] v = [8, 9, 10, 11, 12];
int[] arr = v.remove!(a => a < 10).array;
arr.writeln();
}
- できない
core.bitop
が使える
import core.bitop;
import std.stdio;
void main()
{
immutable ushort x = 0b0001_0110_1110_1111;
writeln(rol(x, 2));
writeln(ror(x, 2));
writeln(popcnt(x));
}
- プロパティ
length
が使える - range(イテレータみたいなもの)に対しては
std.algorithm
やstd.range
の関数が使える
import std.algorithm.mutation : fill;
import std.stdio : writeln;
void f(T)(T c)
{
size_t n = c.length;
c.fill(0);
}
void main()
{
int[] v = [1, 2, 3, 4];
int[4] a = [10, 20, 30, 40];
v.f;
a[].f; // スライスで渡す
v.writeln; // [0, 0, 0, 0]
a.writeln; // [0, 0, 0, 0]
}
__traits(getLocation, ...)
を使う
import std.stdio : writefln;
void main()
{
enum s = __traits(getLocation, main);
writefln("ファイル名: %s", s[0]);
writefln("行番号: %d", s[1]);
writefln("列番号: %d", s[2]);
}
- ビット操作のみを許容するような型はない
- std.bitmanipを使う
- そもそもrangeは範囲をひとつの引数で渡すので特別なことは必要ない
import std.algorithm;
void main()
{
int[] v = [1, 2, 3, 4, 5];
auto b = v.count!"a % 2 == 0";
auto max = v.maxElement;
v.sort; v.fill(5);
}
std.file
を使う
import std.algorithm;
import std.file;
import std.stdio;
void main()
{
if ("test.txt".exists)
copy("test.txt", "test2.txt");
mkdirRecurse("aaa/bbb/ccc");
"test.txt".getSize;
dirEntries("./", SpanMode.depth)
.map!"a.name"
.each!writeln;
}
- 特に制限なく使える
void main()
{
import std.stdio : writefln;
string[] ss = ["aa", "bb", "cc"];
foreach (i, s; ss)
writefln("%d: %s", i, s);
}
-
三方演算子相当はない
-
比較演算子は
opEquals
opCmp
を定義する
struct Date
{
int year, month, day;
// auto refを使えばl-valuesにもr-valuesにも適用される
bool opEquals(auto ref const Date other) const
{
return year == other.year
&& month == other.month
&& day == other.day;
}
int opCmp(ref const Date other) const
{
if (year < other.year) return -1;
else if (year > other.year) return 1;
else if (month < other.month) return -1;
else if (month > other.month) return 1;
else if (day < other.day) return -1;
else if (day > other.day) return 1;
else return 0;
}
}
- ベストプラクティスとして
disable
を用いてdefault constructionを禁止するidiomがある - 以下のように明示的に書く
struct D3D12_VIEWPORT
{
float topLeftX;
float topLeftY;
float width;
float height;
float minDepth;
float maxDepth;
@disable this();
@disable this(this);
this(float topLeftX,
float topLeftY,
float width,
float height,
float minDepth,
float maxDepth)
{
this.topLeftX = topLeftX;
this.topLeftY = topLeftY;
this.width = width;
this.height = height;
this.minDepth = minDepth;
this.maxDepth = maxDepth;
}
}
void main()
{
auto viewport = D3D12_VIEWPORT(
0.0f,
0.0f,
1280.0f,
720.0f,
0.0f,
1.0f);
}
- ない
- そもそもキャプチャを選択はできない
-
これはできない
-
以下のような書き方は可能
import std.meta : AliasSeq;
import std.typecons : Tuple, tuple;
import std.stdio : writefln;
Tuple!(double, double) getTwo()
{
return tuple(35.2, 136.9);
}
void main()
{
double x, y;
AliasSeq!(x, y) = getTwo();
writefln!"%f,%f"(x, y);
}
- これはできない
- これはできない
std.typecons.Nullable
を使う
import std.stdio;
import std.typecons;
void main()
{
Nullable!int oi;
Nullable!int oi2 = 200;
if (!oi.isNull)
oi.get.writeln; // ここは実行されない
if (!oi2.isNull)
oi2.get.writeln;
oi = 100;
oi2.nullify;
if (!oi.isNull)
oi.get.writeln;
if (!oi2.isNull)
oi2.get.writeln; // ここは実行されない
}
std.variant.Algebraic
を使う
import std.stdio : writeln;
import std.variant : Algebraic;
void main()
{
Algebraic!(string, double, bool) v1 = 3.14, v2 = "Hello";
if (v1.type == typeid(double))
writeln(v1.get!1);
if (v2.convertsTo!string)
writeln(v2.get!string);
v2 = true;
writeln(v2.type);
}
- visit関数もある
import std.stdio : writeln;
import std.variant : Algebraic, visit;
void main()
{
Algebraic!(string, double, bool) v1 = 3.14, v2 = "Hello";
auto result = v2.visit!((string s) => s,
(double d) {
import std.conv : to;
return d.to!string;
},
(bool b) => b ? "true" : "false");
result.writeln;
}
static if
とis式
の組み合わせでわりとなんでもできる
import std.stdio;
auto getValue(T)(T t)
{
static if (is(T U : U*))
return *t;
else
return t;
}
void main()
{
int a = 100;
int* p = &a;
a.getValue.writeln;
p.getValue.writeln;
}
- 特殊化テンプレートでも可能
import std.stdio;
auto getValue(T : int)(T t)
{
return t;
}
auto getValue(T)(T t)
{
return *t;
}
void main()
{
int a = 100;
int* p = &a;
a.getValue.writeln;
p.getValue.writeln;
}
template constraints
を使う
import std.math;
import std.stdio;
T mod(T)(T x, T y) if (__traits(isIntegral, T))
{
return x % y;
}
T mod(T)(T x, T y) if (__traits(isFloating, T))
{
return fmod(x, y);
}
void main()
{
mod(12, 5).writeln;
mod(1.75, 1.5).writeln;
}
- 制約の定義も可能
enum isAddable(T) = __traits(compiles, T.init + T.init);
auto add3(T)(T a, T b, T c) if (isAddable!T)
{
return a + b + c;
}
static assert(add3(1, 2, 3) == 6);
- D言語ではCPOは関係がないので省略
- stringは暗黙に参照型で受け渡されるのでとくに注意する必要はない
- おそらくポータブルな方法はない
- GDCやLDCには拡張がある
- より汎用的な
std.conv.to
を使う
import std.conv : to;
import std.stdio : writeln;
void main()
{
double x = 3.141593;
string s = x.to!string;
s.writeln;
}
- より汎用的な
std.conv.parse
を使う
import std.conv : parse;
import std.stdio;
void main()
{
string s1 = "3.14159265358979323";
const d = parse!double(s1);
writefln!"%f"(d);
}
std.format.format
を使う
import std.format : format;
import std.stdio : writeln;
void main()
{
string a = format!"C++ %d"(20);
a.writeln;
}
- enumで受けれるかどうかで判断できる
import std.algorithm : sort;
enum sorted = [15, 30, 10, 5].sort;
static assert(sorted[0] == 5);
__ctfe
で分岐
import std.random;
double sqrt(double x)
{
if (__ctfe)
{
return 1.414; // 手抜き
}
else
{
static import std.math;
return std.math.sqrt(x);
}
}
void main()
{
enum a = sqrt(2.0);
double d = sqrt(uniform(0.0, 1.0));
}
- そもそも全部モジュールでできている
core.thread.fiber
とかstd.concurrency.Generator
を使う
import std.concurrency;
import std.stdio : writeln;
void main()
{
auto r = new Generator!int({
foreach (i; 0..10)
yield(i);
});
foreach (i; r)
writeln(i);
}
in
で事前条件を、out
で事後条件を指定
double sqrtChecked(double x)
in(x >= 0)
out(r; r >= 0)
do
{
static import std.math;
return std.math.sqrt(x);
}
void main()
{
auto r = sqrtChecked(-1.0);
}
- できない