概要
Dとは何か?

Dは汎用のシステムおよびアプリケーション・プログラミング言語である。 高レベル言語でありながら、高性能なコードを書く能力を保持している。 高性能なコードを記述し、オペレーティング・システムと直接インターフェイスする能力を保持している。 オペレーティング・システム API およびハードウェアと直接インターフェイスする能力を保持している。 Dは中規模から大規模のプログラムを書くのに適している。 万行のプログラムを開発者チームで書くのに適している。Dは習得が容易である。 Dは習得が容易で、プログラマーを支援する多くの機能を備えている、 また、積極的なコンパイラ最適化技術に適している。
D言語はスクリプト言語でもインタプリタ言語でもない。 また VMもない、 宗教があるわけでもない。 哲学もない。実用的なプログラマーのための実用的な言語なのだ。 素早く、確実に仕事をこなし、保守可能で理解しやすいコードを残す必要がある 保守可能で理解しやすいコードを残す必要がある。
Dは、多種多様な言語のコンパイラを実装し コンパイラを実装し、それらの言語を使って大規模なプロジェクトを構築しようとした数十年の経験の集大成である。 Dは、多種多様な言語用のコンパイラを実装し、それらの言語を使って大規模なプロジェクトを構築しようとした数十年の経験の集大成だ。Dはこれらの言語(特にC++)からインスピレーションを得ている。 Dは、そうした他の言語(特にC++)からインスピレーションを受け、それを経験と実世界での実用性で和らげる。 経験と実世界での実用性を加味している。
なぜDなのか?
確かにそうだ。他のプログラミング言語が必要だろうか?
ソフトウェア業界は猛烈なスピードで進化し続けている。 新しいアイディアが登場し、古いアイディアが検証されたり捨てられたりする。 プログラマーがプログラミング言語に求めるものは変化する。 利用可能なメモリとコンピューティング・パワーは桁外れに増大している。 また、開発されるプログラムの規模も桁違いに大きくなっている。
コンパイラーはもはや、利用可能なコンピューティング・リソースに大きく制約されることはない。 そのため、プログラマーのために多くのことができるようになった。 より強力な言語機能が実用的になった。 これらの機能を既存の言語に後付けするのは難しいかもしれない、 これらの機能が十分にあれば、新しい言語が正当化される。
Dの主な設計目標
言語を設計する上で、すべてはトレードオフである。いくつかの いくつかの原則を念頭に置くことは、正しい決断を下すのに役立つ。
- 高速で効果的なコードをわかりやすく書けるようにする。
- コンパイラからコンパイラへ、マシンからマシンへ、オペレーティング・システムからオペレーティング・システムへ移植可能なコードを書きやすくする。 コンパイラからコンパイラへ、マシンからマシンへ、オペレーティング・システムからオペレーティング・システムへ移植可能なコードを書きやすくする。 システム間で移植可能なコードを書きやすくする。未定義の動作や処理系の定義:" をできるだけ排除する。 をできるだけ排除する。
- よくある間違いをなくすか、少なくとも減らすような構文的・意味的構造を提供する。 よくあるミスを少なくとも減らす。サードパーティの静的コードチェッカーの必要性を減らすか、あるいはなくす。 サードパーティの静的コードチェッカの必要性を減らす。
- メモリーセーフプログラミングをサポートする。
- マルチパラダイム・プログラミングをサポートする。 命令型、構造型、オブジェクト指向、ジェネリック、さらには 関数型プログラミング・パラダイムをサポートする。
- 間違った方法よりも正しい方法の方が簡単である。
- C、C++、Javaでのプログラミングに慣れているプログラマーにとって、学習曲線が短いこと。 C、C++、またはJavaでのプログラミングに慣れているプログラマーにとって、学習曲線が短いこと。
- 必要に応じて、低レベルのベアメタルアクセスを提供する。高度なプログラマーが 上級プログラマが必要に応じてチェックを逃れる手段を提供する。
- ローカルのCアプリケーション・バイナリ・インターフェースと互換性がある。
- DコードがCコードと同じに見える場合は、同じ動作をするか、エラーを出すようにする。 同じ動作をさせるか、エラーを出させる。
- 文脈自由文法を持つ。構文解析を成功させるためには 意味解析を必要としないこと。
- 国際化されたアプリケーションの作成を容易にサポートする。
- 契約プログラミングとユニットテスト手法を取り入れること。
- 軽量でスタンドアロンなプログラムを構築できること。
- ドキュメント作成のコストを削減する。
- コンパイラ最適化技術の進歩を可能にする十分なセマンティクスを提供する。 技術に対応する。
- 数値解析プログラマーのニーズに応える。
- もちろん、これらの目標が矛盾することもある。解決策は 使いやすさを優先する。
Dへの移行
Dの一般的な外観はCやC++に似ている。そのため C/C++からDへの移行は自然に感じられるはずだ。 プログラマーは プログラマーは、まったく新しいやり方を学ぶ必要はない。
Dを使うことは、プログラマーがJava vmや仮想マシンのような特殊なランタイムvm(仮想マシン)に制限されることを意味しない。 Dを使うことは、プログラマーがJava vmやSmalltalk vmのような特殊なランタイムvm(仮想マシン)に制限されることを意味しない。 のような特殊なランタイムvm(仮想マシン)に制限されることはない。 D vmは存在しない。 リンク可能なオブジェクト・ファイルを生成する。 DはCと同じようにオペレーティング・システムに接続する。 make Dは、Cと同じようにオペレーティング・システムに接続する。 Dでの開発にぴったりだ。
- C/C++の一般的なlook and feel 。 C/C++の一般的な構文が採用されている。 と文の形式、そして一般的なレイアウトを使用する。
- Dプログラムは使い慣れたパラダイムで書くことができる、 function-and-data, object-oriented, template metaprogramming, functional, またはそれらのミックスで書くことができる。
- compile/link/debug の開発モデルは Cのような言語から継承されている、 Dがバイトコードにコンパイルされ、解釈されることを妨げるものはない。 にコンパイルされ、解釈されることを妨げるものではない。
- Exception handling. 例外処理の経験が増えれば増えるほど、例外処理はエラーコードよりも優れたエラー処理方法であることがわかる。 エラーコードよりも優れたエラー処理方法であることを示している。
- Runtime Type Identification. RTTIを完全にサポートすることで、より優れたガベージコレクションが可能になる。 より良いガベージコレクション、より良いデバッガーサポート、より自動化された永続性などが可能になる。
- DはC calling conventions との関数リンク互換性を維持している。 これは、Dプログラムがオペレーティング・システムAPIに直接アクセスすることを可能にする。 プログラマーは、既存のプログラミングAPIやパラダイムに関する知識と経験を引き継ぐことができる。 やパラダイムに関するプログラマーの知識や経験は、最小限の労力でDに引き継ぐことができる。
- 関数リンクの互換性については、C++ calling conventions との限られたサポートしかない。 特に、以下の互換性がある。 C++の名前マングリング、名前空間、テンプレート、例外との互換性がある。
- Operator overloading. Dプログラムは演算子をオーバーロードすることができる。 基本型をユーザー定義型で拡張できる。
- Template Metaprogramming. パラメトリック・ポリモーフィズム(別名テンプレート・メタプログラミング)はDでは簡単である。 である。
- RAII (リソース獲得は初期化である)。 RAIIテクニックは、信頼性の高いソフトウェアを書くために不可欠な要素である。 ソフトウェアに不可欠な要素である。
- Custom memory management. システム・プログラミングでは、開発者がガベージコレクションに代わるものを必要とする場合がある。 システム・プログラミングでは、開発者がガベージコレクションに代わるものを必要とする場合がある。Dでは、手動によるメモリ管理も可能だ。 Dはまた、手作業によるメモリ管理、参照カウントのようなテクニック、特殊なメモリ・アロケーターの使用も可能にしている。 特化したメモリ・アロケータを使用することもできる。
- Down and dirty programming.Dは、以下の能力を保持している。 Dは、別の言語でコンパイルされた外部モジュールを参照することなく、本格的なプログラミングを行う能力を保持している。 Dは、別の言語でコンパイルされた外部モジュールを参照することなく、実戦的なプログラミングを行う能力を保持している。時には、ポインターを強要したり、アセンブラに浸ったりする必要があることもある、 ポインターを強要したり、アセンブリに浸ったりする必要があることもある。 を使う必要がある。D言語の目標は、ダウン&ダーティ・プログラミングを防ぐことではない。 D言語の目標は、ダーティなプログラミングを防ぐことではなく、日常的なコーディング作業を解決する上で、プログラミングの必要性を最小限に抑えることだ。 日常的なコーディング作業を解決することである。
残すべき機能
- 16ビットコンピューターをサポートする。 Dではニア/ファー・ポインタの混在や、優れた16ビット・コードを生成するために必要なあらゆる工夫は考慮されていない。 優れた16ビットコードを生成するために必要なあらゆる工夫がなされていない。D言語 の設計は、少なくとも32ビットのフラットなメモリ空間を想定しており、64ビットもサポートしている。 もサポートしている。
- コンパイラー・パスの相互依存。 レキサー、パーサー、セマンティック・パスがきれいに分離されている。 パスがきれいに分離されていることで、より実装しやすく理解しやすい言語になる。 これは、ユーザー定義のトークンやユーザー定義の構文がないことを意味する。
- マクロ・システム。 マクロは、ユーザーが非常に強力な機能を追加する簡単な方法である。 しかし残念なことに、その複雑さはマクロの使い方を理解しようとするユーザーに押しつけられる。 マクロの使い方を理解しようとするユーザーに複雑さを押し付けてしまう。 正当化できない。
- C/C++ソースコードの互換性。 プリプロセッサの使用により、これを実現するのは難しくなっている。 必然的に手作業によるタッチアップが必要となる。これは外部ツールに任せるのがベストだ。 を外部ツールに任せるのがベストだ。
- 多重継承。これは複雑で な機能であり、その値には議論の余地がある。効率的な方法で実装するのは非常に難しい。 効率的な方法で実装するのは非常に難しく、コンパイラーはそれを実装する際に多くのバグを起こしやすい。 を起こしやすい。のほぼすべての値は、MIで処理できる。 MIは 単一継承 インターフェイスや集約と組み合わせることで対処できる。残されたものは、MI実装の重さを正当化するものではない。 MIの実装の重さを正当化するものではない。
Dは誰のためにあるのか?
- lintや同様のコード解析ツールを日常的に使用しているプログラマー。 を日常的に使用しているプログラマ。
- 警告レベルを最大にしてコンパイルし、警告をエラーとして扱うようコンパイラに指示する。 警告をエラーとして扱うようにコンパイラに指示する。
- よくあるバグを避けるために、プログラミング・スタイル・ガイドラインに頼らざるを得ないプログラミング・マネージャー。 ガイドラインに頼らざるを得ない。
- 組み込みのテストや検証が必要なプロジェクト。
- 100万行のコードを含むアプリを書くチーム。
- 言語が十分な機能を提供するべきだと考えているプログラマー。 プログラマー。 ポインターを直接操作する必要性を排除するのに十分な機能を提供すべきだと考えるプログラマー。
- アプリケーションの半分をスクリプト言語で書くプログラマー。 プログラマーは、アプリケーションの半分をスクリプト言語で書き、残りの半分をネイティブ言語で書く。 ボトルネックをスピードアップする。 Dには、このようなハイブリッド・アプローチを不要にする生産性機能がある。 がある。
- Dの"語彙"解析器と構文解析器は、互いに、また意味解析器とも完全に独立している。 意味解析器から完全に独立している。つまり、完全なコンパイラーを作らなくても、D言語のソースを完璧に操作する簡単なツールを書くことができる。 を完全に操作するための簡単なツールを、完全なコンパイラを作ることなく簡単に書くことができる。また、ソースコードを トークン化された形で転送することができる。
Dは誰のためにあるのか?
- 現実的には、100万行のレガシー・プログラムをDに変える人はいない。 現実的には、100万行のレガシープログラムをDに変換する人はいない。 しかしDは、C ABIインターフェイスを公開するコードや、(限られた範囲ではあるが)C++ ABIインターフェイスを公開するコードに直接接続することができる。 または(限られた範囲ではあるが)C++とのインターフェイスを公開しているコードには直接接続できる。
- 最初のプログラミング言語としては、PythonやJavaScriptの方が適している。 が適している。D言語は、中級から上級のプログラマーにとって優れた第2言語となる。 Dは、中級から上級のプログラマーにとって優れた第2言語となる。
- 言語純粋主義者。D言語は実用的な言語である。 Dは実用的な言語であり、D言語の各機能は理想ではなく、その観点から評価される。 例えば、Dは通常の作業でポインターを事実上使用しない構成とセマンティクスを持っている。 通常のタスクではポインターは必要ない。しかし 時にはルールを破る必要があるからだ。 同様に、型付けシステムをオーバーライドする必要がある場合のために、キャストも存在する。 をオーバーライドする必要がある場合のために存在する。
Dの主な特徴
このセクションでは、様々なカテゴリーにおけるD の興味深い機能をさまざまなカテゴリーに分けて紹介する。
オブジェクト指向プログラミング
クラス
Dのオブジェクト指向はクラスからきている。 継承モデルは、インターフェイスで強化された単一継承である。 インターフェースで強化されている。クラスObjectは継承階層のルートに位置する。 クラスが継承階層のルートに位置する。 を実装している。 クラスは参照によってインスタンス化される。 クラスは参照によってインスタンス化される。 は必要ない。
詳しくはクラスのページを参照のこと。 を参照のこと。
演算子オーバーロード
新しい型をサポートするように型システムを拡張するために、既存の演算子と連動するクラスを作ることができる。 新しい型をサポートするために型システムを拡張する。例としては、次のようなものがある。 をオーバーロードして、通常の代数構文を使えるようにする。 をオーバーロードして、通常の代数構文を使えるようにする。
演算子オーバーロード」のページを参照のこと。 のページを参照のこと。
関数型プログラミング
関数型プログラミングには、カプセル化という点で多くの利点がある、 関数型プログラミングには、カプセル化、並行プログラミング、メモリ安全性、コンポジションなど、多くの利点がある。関数型プログラミングに対する Dは関数型プログラミングをサポートしている:
- 純粋関数
- 不変の型とデータ構造
- ラムダ関数とクロージャ
生産性
モジュール
ソース・ファイルはモジュールと1対1で対応している。
モジュール のページを参照のこと。
宣言と定義
関数とクラスは一度だけ定義される。前方参照される場合は 宣言は必要ない。 モジュールはインポートすることができ、そのすべてのパブリック宣言はインポーターが利用できるようになる。 をインポートすることができる。
例:
class ABC { int func() { return 7; } static int z = 7; } int q;
すべてのメンバはクラスまたは構造体の中で定義され、個別に定義されることはない。
class Foo { int foo(Bar c) { return c.bar; } } class Bar { int bar() { return 3; } }
D関数がインライン化されるかどうかは、オプティマイザの設定によって決まる。 オプティマイザの設定によって決まる。
テンプレート
Dテンプレートは、ジェネリック・プログラミングをサポートしながら、部分的な特殊化の力を提供するクリーンな方法である。 部分的な特殊化の力を提供する。 テンプレート・クラスとテンプレート関数が利用できる。 可変長引数やタプルも利用できる。
テンプレート のページを参照のこと。
連想配列
連想配列とは、整数インデックスに限定されず、任意のデータ型をインデックスとする配列のことである。 をインデックスとする配列である。 要するに、連想配列はハッシュ・テーブルである。連想 配列は、高速で効率的でバグのないシンボル・テーブルを簡単に構築できる。 テーブルを簡単に構築できる。
連想配列 のページを参照のこと。
ドキュメンテーション
ドキュメンテーションは伝統的に2回行われてきた。 まず、その関数が何をするのかを説明するコメントがある。 その後、別のhtmlやmanページに書き換える。 そして当然ながら、時間が経つにつれて、コードが更新されても別のドキュメントが更新されないため、両者は乖離する傾向がある。 が更新され、別のドキュメントが更新されなくなる。 ソースに埋め込まれたコメントから、必要な洗練されたドキュメントを直接生成することができる。 ソースに埋め込まれたコメントから、必要な洗練されたドキュメントを直接生成することができれば、ドキュメントの準備に必要な時間を半分に短縮できるだけでなく、次のような利点もある。 ドキュメントの準備に必要な時間を半分に短縮できるだけでなく、次のことも容易になる。 ドキュメントをコードと同期させることができる。 DdocはD ドキュメント・ジェネレーターの仕様である。このページもDdocによって生成された。
サードパーティ製のツールは他の言語にも存在する。 これらにはいくつかの重大な欠点がある:
- 言語を正しく解析するのが難しい。 サードパーティのツールは サードパーティーのツールは、ある言語のサブセットしか正しく解析しない傾向がある。 ソースコードがそのサブセットに制約される。
- コンパイラーによって、サポートする言語のバージョンや拡張機能が異なる。 拡張が異なる。サード・パーティ製ツールは、このような サードパーティ製ツールには、こうしたすべてのバリエーションに対応する問題がある。
- サードパーティのツールは、希望するすべてのプラットフォームで利用できるとは限らない。 サードパーティーのツールは、希望するすべてのプラットフォームで利用できるとは限らない。 コンパイラーとは異なるアップグレードサイクルである。
- コンパイラーに組み込まれているということは、すべてのD実装で標準化されているということだ。 すべてのD実装で標準化されているということだ。デフォルトのものがいつでも使える状態になっている。 ということは、それが使われる可能性がはるかに高いということだ。
関数
D言語は、以下のような通常の関数をサポートしている。 グローバル関数、オーバーロード関数、関数のインライン化、 メンバ関数、仮想関数、関数ポインタなどである。 加えて
ネストされた関数
関数は他の関数の中に入れ子にすることができる。 これは、コード・ファクタリング、局所性、関数クローズ・テクニックに非常に有用である。 関数クロージャのテクニックに大いに役立つ。
関数リテラル
匿名関数は式に直接埋め込むことができる。
ダイナミック・クロージャー
ネストされた関数やクラスのメンバ関数は、クロージャ(デリゲートとも呼ばれる)で参照することができる。 クロージャ(デリゲートとも呼ばれる)で参照できる。 をより簡単に、型安全にする。
イン、アウト、レフ・パラメーター
を指定することで、関数をより自己文書化しやすくするだけでなく、ポインタの必要性もほとんどなくなる。 ポインタの必要性がほとんどなくなる。 ポインタの必要性がほとんどなくなる。 また、コーディング上の問題を発見するためにコンパイラが手助けしてくれる可能性が広がる。
これにより、Dはより多様な海外APIと直接インターフェイスできるようになった。 Dがより多様な海外APIと直接インターフェイスできるようになる。インターフェイス定義言語」のような回避策は必要ない。 インターフェース定義言語」のような回避策は必要なくなる。
配列
Cの配列には修正可能な欠陥がいくつかある:
- 次元情報は配列と一緒に持ち運ばれない。 そのため、別々に格納し、渡す必要がある。 その典型的な例が、argcとargvである。 パラメータである。 main(int argc, char *argv[]). (Dでは、mainは main(string[] args).)
- 配列はファーストクラスのオブジェクトではない。配列が関数に渡されるとき、それはポインタに変換される。 配列が関数に渡されると、それはポインタに変換される。 配列である。この変換が行われると、配列の型情報はすべて失われる。 が失われてしまう。
- C言語の配列はサイズを変更することができない。これは、スタックのような単純な集合体でさえも、複雑なクラスとして構築する必要があることを意味する。 のような単純な集合体であっても、複合クラスとして構築する必要がある。
- Cの配列は境界チェックができない。 なぜなら、配列の境界がわからないからだ。
- 配列は識別子の後に[]を付けて宣言される。これは
非常に不便だ。
配列へのポインタのようなものを宣言する構文が非常に不格好になる:
int (*array)[3];
Dでは、配列の[]は左側にある:
int[3]* array; // 3つのintの配列へのポインタを宣言する long[] func(int x); // longの配列を返す関数を宣言する
の方がはるかにシンプルだ。
D配列には、ポインタ、静的配列、動的配列、連想配列などの種類がある。 配列、そして連想配列である。
詳しくは配列のページを参照のこと。
文字列
文字列操作 は、言語で直接サポートする必要がある。最近の言語では 文字列の連結、コピーなどを扱う。 は、配列処理の改良の直接的な結果である。
レンジ
D言語では、他の言語に見られるイテレーターやジェネレーターの代わりに、レンジという概念を使用している。 の代わりに、範囲という概念を使う。範囲とは、一連の値に対する共通のインターフェイスを提供するあらゆる型のことである。 型のことである。レンジの目的は、任意のデータに対して動作するコードをよりシンプルに記述できるようにすることである。 任意のデータに対して動作するコードをより単純な方法で書けるようにし、それによって再利用性を高めることにある。
最も基本的な型は入力範囲と呼ばれる、 これは3つのメソッドを提供する。
struct MyRange { auto front() { // 配列の次の値を返す } void popFront() { // シーケンスの先頭を次の値に移動する } bool empty() { // 返す値がもうない場合はtrueを返す } }
このシンプルなインターフェイスのパワーを理解するために、例を挙げてみよう。 例を見てみよう。例えば、ある会社の全従業員を対象に、40歳以下の従業員を除外し、残りの従業員を次のようなグループに分けるプログラムを書きたいとする。 ある会社の全従業員を取り出し、40歳未満の従業員を除外し、残りの従業員を所属組織別に配列にグループ化するプログラムを書きたいとする。 の配列にグループ化する。
struct Employee { uint id; uint organization_id; string name; uint age; } struct Employees { Employee[] data; this(Employee[] employees) { data = employees; } Employee front() { return data[0]; } void popFront() { data = data[1 .. $]; } bool empty() { return data.length == 0; } }
ここでは、単純な例としてコンストラクターからデータを取得しているが、CSVやデータベースなど、どのようなソースからでも取得できる。 CSVやデータベースのように、どのようなソースからでも来る可能性がある。
D.D.では、基本的な動的配列も範囲として機能する、 Dでは基本的な動的配列も範囲として機能するため、範囲を受け付けるアルゴリズムはすべて配列も受け付けることになる。 Dでは基本的な動的配列も範囲として機能する。しかし、静的配列は範囲とはみなされない、 というのも、popFront の操作は、範囲の長さを変更することに基づいているからだ、 これは静的配列では不可能である。静的配列から範囲を取り出すには、次のようにする、 のように、すべての要素を含むスライスを作成する:
int[4] array = [1, 2, 3, 4]; // 範囲ではない array[]; // 有効範囲
これで範囲が定義されたので、その範囲に入力し、フィルタリング・コードを書くことができる。
void main() { import std.algorithm.iteration : filter, chunkBy; Employees employees = Employees([ Employee(1, 1, "George", 50), Employee(2, 3, "John", 65), Employee(3, 2, "David", 40), Employee(4, 1, "Eli", 40), Employee(5, 2, "Hal", 35) ]); auto older_employees = employees .filter!(a => a.age > 40) // D のラムダは=>構文を使用する .chunkBy!((a,b) => a.organization_id == b.organization_id); }
std.algorithmに含まれるすべてのアルゴリズムは、プロジェクトごとに共通の機能を書き直すという問題を避けるために、範囲を使って動作する。 std.algorithmはソート、フィルター、マップ、リダクションなどを実装している。 はソート、フィルター、マップ、リダクションなどを実装している。
従業員構造体は入力範囲の定義に準拠している、 foreach ループでも使用できる。 渡された値が入力範囲かどうかを自動的に検出する。
foreach(employee; employees)
{
writeln(employee);
}
と等価である。
for(; !employees.empty; employees.popFront())
{
writeln(employees.front);
}
レンジの型
入力レンジはレンジの最も基本的な形態に過ぎない。
- 順方向レンジ
- 双方向レンジ
- ランダムアクセスレンジ
- 出力レンジ
これらの範囲はそれぞれ、基礎となるデータへのアクセス方法を示している。 これらの範囲はそれぞれ、基礎となるデータにアクセスする明確な方法を表している。出力範囲の場合は、データを別のソースに送信する方法である。 を別のソースに送信する方法である。各範囲の型についての詳細は 範囲プリミティブ のページを参照のこと。
これらの範囲型はそれぞれ、標準ライブラリの異なるアルゴリズムにアクセスできる。 にアクセスできる。例えば、入力範囲に対してフィルタを実行することができる。 で実行できるが、ソートはできない。 スライス演算子オーバーロード "が定義されたランダムアクセス範囲を必要とする。各関数の要件は、以下の関数のシグネチャで確認できる。 各関数の要件は、ドキュメントのテンプレート化された関数のシグネチャで見ることができる。 制約を参照すること。テンプレート ページと上記の範囲プリミティブのリンクを参照のこと。 を参照のこと。
前述したように、Dにおける動的配列と連想配列は範囲として機能する。 の範囲として機能する。具体的には、これらはランダム・アクセス範囲である。 std.algorithmのどの関数も、これらの基本的な型を扱うことができる。
高度なレンジコード
以下の例では、入力範囲と出力範囲を使って、stdinからデータを取り込む。 stdinからデータを受け取り、ユニークな行だけを取り出してソートし、結果を 結果を標準出力に出力する。
// 行を並べ替える import std.stdio; import std.array; import std.algorithm; void main() { stdin .byLine(KeepTerminator.yes) .uniq .map!(a => a.idup) .array .sort .copy(stdout.lockingTextWriter());
範囲ベースのコードの例については、『Ali. レンジの章を参照のこと。 Çehreliの著書 "Programming In D"のRangesの章を参照のこと。また H. S. Teoh著「Component programming with ranges」も参照のこと。
資源管理
自動メモリー管理
Dメモリの割り当ては完全にガベージコレクションされる。 ガベージコレクションによって、プログラミングはよりシンプルになる。 ガベージコレクションを使えば、面倒でエラーの起きやすいメモリ割り当て追跡コードが不要になる。 ガベージ・コレクションによって、面倒でエラーの起きやすいメモリ割り当ての追跡コードが不要になる。これは次のことを意味するだけではない。 開発時間が大幅に短縮され、メンテナンス・コストが削減される、 その結果、プログラムは頻繁に実行される が速くなる。
これについての詳しい議論は ガベージコレクションを参照のこと。
明示的なメモリー管理
D言語はガベージコレクション言語であるが、newとdeleteは特定のクラスに対してオーバーライドすることができる。 操作を特定のクラスに対してオーバーライドすることができる。 カスタム・アロケータを使うことができる。
RAII
RAIIは、リソースの割り当てと割り当て解除を管理する最新のソフトウェア開発技法である。 RAIIは、リソースの割り当てと割り当て解除を管理する最新のソフトウェア開発手法である。Dは、ガベージコレクションとは独立した、制御された予測可能な方法でRAIIをサポートする、 Dは、ガベージコレクションサイクルから独立した、制御された予測可能な方法でRAIIをサポートする。 サイクルをサポートする。
パフォーマンス
軽量骨材
DはシンプルなC言語のスタイル "構造体"をサポートしている。 Cのデータ構造との互換性を保つためと、クラスをフルに使うのが面倒なときに便利だからだ。 クラスの全パワーが過剰な場合に便利だからだ。
インラインアセンブラ
デバイス・ドライバ、高性能システム・アプリケーション、組み込みシステム、 特殊なコードなどでは、アセンブラ言語が必要になることがある。 に触れる必要がある。D実装はインライン・アセンブラを実装する必要はないが D実装はインライン・アセンブラを実装する必要はないが、インライン・アセンブラは定義されており、言語の一部となっている。 言語の一部である。インライン・アセンブラは定義されており、言語の一部である、 別個のアセンブラやDLLを必要としない。
多くのD実装は、組込み関数もサポートする。 C言語がI/Oポート操作のための組込み関数をサポートしているのと同様である、 特殊な浮動小数点演算への直接アクセスなどである。
インラインアセンブラ」のページを参照のこと。 のページを参照のこと。
信頼性
最新の言語は、プログラマーがコードのバグを洗い出すのを助けるために、できる限りのことをすべきである。 は、プログラマーがコードのバグを洗い出すのを助けるために、できる限りのことをしなければならない。その手助けには様々な形がある; よりロバストなテクニックを使いやすくする、 明らかに正しくないコードをコンパイラがフラグを立てたり、ランタイム・チェックをしたりすることだ。
契約
契約プログラミング (バートランド・メイヤー博士によって考案された)は、次のような手法である。 技術である。 プログラムの正しさを保証する技術である。Dバージョンの 関数の前提条件、関数の後条件、クラスの不変量、アサート契約などがある。 invariants、assert契約などがある。 Dの実装については「契約」を参照のこと。
単体テスト
ユニット・テストをクラスに追加して、プログラム起動時に自動的に実行されるようにすることができる。 に追加することができる。これは、ビルドのたびに、クラスの実装が不注意で壊れていないかどうかを検証するのに役立つ、 これは、ビルドのたびに、クラスの実装が不注意で壊れていないことを確認するのに役立つ。ユニット ユニット・テストは、クラスのソース・コードの一部を形成する。これを作成する を作成することは、クラス開発プロセスの自然な一部となる。 完成したコードをテスト・グループに壁越しに投げるのとは対照的だ。
ユニットテストは他の言語でもできる。 他の言語でもユニットテストはできる。 ユニットテストはD言語の大きな特徴である。 関数が実際に動作することを保証すると同時に、関数がどのように動作するかを説明することができる。 関数が実際に動作することを保証すると同時に、関数の使い方を説明するのにも役立つ。
ウェブ上でダウンロードできる多くのライブラリやアプリケーションのコードベースを考えてみよう。 を考えてみよう。その中に、単体テストはおろか 単体テストはおろか、検証テストがまったくないものはどれくらいあるだろうか?通常のやり方は コンパイルできれば動くと考えるのが普通だ。そして、その過程でコンパイラが吐き出す警告は、本当のバグなのか、それとも単なるバグなのか。 コンパイラが吐き出す警告が本当のバグなのか、それとも単なるお喋りなのか。 なのだろうか。
契約プログラミング "と並んで、ユニットテストは、D言語を、信頼性の高い堅牢なシステム・アプリケーションを書くための最高の言語にしている。 は、信頼性が高く堅牢なシステム・アプリケーションを書くのに最適な言語である。 単体テストはまた、私たちの目の前に落ちてきた未知のDコードの品質を、素早く簡単に見積もることもできる。 もしユニットテストもコントラクトもなければ、それは受け入れがたいものだ。 ユニットテストも契約もなければ、それは受け入れがたいものだ。
ユニットテスト のページを参照のこと。
デバッグ属性とステートメント
今やデバッグは言語の構文の一部である。 このコードは、マクロや前処理コマンドを使わずに、コンパイル時に有効にも無効にもできる。 マクロや前処理コマンドを使用することなく、コンパイル時にコードを有効にも無効にもできる。デバッグ構文は以下を可能にする。 一貫性があり、移植性があり、理解しやすい。 実際のソースコードは、デバッグ・コンパイルとリリース・コンパイルの両方を生成できる必要がある。 リリース・コンパイルの両方を生成できる必要がある。
例外処理
単なるtry-catch-finallyモデルではなく、優れたtry-catch-finallyモデルが使われる。 が使われる。デストラクタにfinallyセマンティクスを実装させるためだけにダミー・オブジェクトを作る必要はない。 デストラクタにfinallyセマンティクスを実装させるためだけにダミーオブジェクトを作る必要はない。
同期化
マルチスレッド・プログラミングが主流になりつつある、 Dはマルチスレッド・プログラムを構築するためのプリミティブを提供している。 同期はメソッド・レベルでもオブジェクト・レベルでも行える。
synchronized int func() { ... }
同期関数は、一度に1つのスレッドだけがその関数を実行できる。 その関数を実行することができる。
synchronizeステートメントは、ステートメントのブロックにミューテックスを置く、 オブジェクト単位またはグローバルにアクセスを制御する。
ロバスト技術のサポート
- ポインターの代わりに動的配列
- ポインターの代わりに参照変数
- ポインターの代わりに参照オブジェクト
- 明示的なメモリ管理の代わりにガベージコレクションを使用する。
- スレッド同期用の組み込みプリミティブ
- コードを不用意に乱すマクロがない。
- マクロの代わりにインライン関数
- ポインタの必要性が大幅に減る
- 積分型のサイズが明示される
- 文字が符号付きかどうかの不確実性がなくなる
- ソースファイルとヘッダーファイルで宣言を重複させる必要がない。
- デバッグ・コードを追加するための明示的な解析サポート。
コンパイル時のチェック
- より強力な型チェック
- 空のforループ本体がない
- 代入はブール値の結果を返さない
- 廃止されたAPIの廃止
ランタイム・チェック
- assert()式
- 配列の境界チェック
- switch例外の未定義ケース
- メモリ不足例外
- イン、アウト、クラス不変性 契約プログラミングのサポート
互換性
演算子の優先順位と評価ルール
DはC演算子とその優先規則、評価順序、昇格規則を保持する。 評価ルール、および昇格ルールを保持する。これによって、C言語の演算子に慣れきっているために起こりうる微妙なバグを避けることができる。 これは、C言語のやり方に慣れすぎているために発生する微妙なバグを回避するためである。 のやり方に慣れているために、意味論の違いによるバグを見つけるのに苦労するような微妙なバグを避けることができる。 を見つけるのに非常に苦労することになる。
C APIへの直接アクセス
DはCのデータ型に対応するデータ型を持っているだけではない、 C関数への直接アクセスを提供する。そのため ラッパー関数やパラメータ・スウィズラーを書く必要もないし、集合体メンバをひとつひとつコピーするコードも必要ない。 を書く必要もない。
すべてのCデータ型をサポートする
あらゆるC APIや既存のC言語とのインターフェイスを可能にする。 ライブラリコードとのインタフェースを可能にする。このサポートには、構造体、共用体、列挙型、ポインタ、すべてのC99型が含まれる、 ポインタ、すべてのC99型が含まれる。 Dには以下の機能がある。 Dには、構造体メンバのアラインメントを設定する機能がある。 Dには、構造体メンバのアライメントを設定する機能がある。
OSの例外処理
Dの例外処理メカニズムは、以下のようなOSの例外処理方法に対応している。 の例外処理メカニズムに接続する。 に接続する。
既存のツールを使う
Dは標準的なオブジェクト・ファイル形式でコードを生成する。 標準的なアセンブラ、リンカ、デバッガ、プロファイラ、exeコンプレッサを使用できる、 また、他の言語で書かれたコードとリンクすることもできる。 また、他の言語で書かれたコードとリンクすることもできる。
プロジェクト管理
バージョン管理
Dは、同じテキストから複数のバージョンのプログラムを生成する の生成をサポートしている。これは、Cプリプロセッサ #if/#endifテクニックに取って代わる。
非推奨
時間の経過とともにコードが進化するにつれて、古いライブラリ・コードの一部は新しいバージョンに置き換えられる。 より新しく、より良いバージョンに置き換えられる。古いバージョンは、レガシーコードをサポートするために 古いバージョンは、レガシーコードをサポートするために利用可能でなければならないが、非推奨とマークすることもできる。 非推奨のバージョンを使用するコードは、通常、違法と判定される。 しかし、コンパイラー・スイッチによって許可される。 これにより、メンテナンス・プログラマーは プログラマーは、非推奨機能への依存を特定しやすくなる。
サンプルDプログラム(sieve.d)
/* Sieve of Eratosthenes prime numbers */ import std.stdio; void main() { size_t count; bool[8191] flags; writeln("10 iterations"); // iterを捨て変数として使う foreach (iter; 1 .. 11) { count = 0; flags[] = 1; foreach (index, flag; flags) { if (flag) { size_t prime = index + index + 3; size_t k = index + prime; while (k < flags.length) { flags[k] = 0; k += prime; } count += 1; } } } writefln("%d primes", count); }
注意:配列のインデックスx が数値xを表していると予想されるかもしれないが、i + i + 3 は一見奇妙に見える。 しかし、それぞれのインデックスを考えてみると、最初の要素は0 + 0 + 3 = 3を表すことになる; 番目の要素は1+1+3=5を表す; 3番目の要素は2+2+3=7を表す; といった具合である。 つまり、この配列で表される数字は、実際には3から(8190 + 8190 + 3)、つまり16383までとなる。
DEEPL APIにより翻訳、ところどころ修正。
このページの最新版(英語)
このページの原文(英語)
翻訳時のdmdのバージョン: 2.108.0
ドキュメントのdmdのバージョン: 2.109.1
翻訳日付 :
HTML生成日時:
編集者: dokutoku