「D言語」の版間の差分

出典: フリー教科書『ウィキブックス(Wikibooks)』
削除された内容 追加された内容
Angol Mois (トーク | 投稿記録)
型をより大きいセクションへ
Angol Mois (トーク | 投稿記録)
M typo
38 行 38 行
C++ と違って <code>cout</code> の後ろの<nowiki> << </nowiki> の方向が <nowiki> >> </nowiki> だったかそれとも <nowiki> << </nowiki> だったかで悩む必要もD言語では無く、直感的にD言語は扱いやすく設計されています。
C++ と違って <code>cout</code> の後ろの<nowiki> << </nowiki> の方向が <nowiki> >> </nowiki> だったかそれとも <nowiki> << </nowiki> だったかで悩む必要もD言語では無く、直感的にD言語は扱いやすく設計されています。


C++ や言語との重要な違いはテンプレートです。テンプレート引数を <nowiki> < > </nowiki> で表すと、構文解析の際にそれがテンプレートの引数なのかそれとも比較式なのかを、記号表をいちいちチェックしなければならず、パースの時間が非常に長くなってしまいます。D言語は <code>!</code> が二項演算子として使われていないことに着目して、これをきれいに解決しました。
C++ や言語との重要な違いはテンプレートです。テンプレート引数を <nowiki> < > </nowiki> で表すと、構文解析の際にそれがテンプレートの引数なのかそれとも比較式なのかを、記号表をいちいちチェックしなければならず、パースの時間が非常に長くなってしまいます。D言語は <code>!</code> が二項演算子として使われていないことに着目して、これをきれいに解決しました。


== Hello World! ==
== Hello World! ==

2020年6月22日 (月) 15:32時点における版

情報技術 > プログラミング > D言語


Wikipedia
Wikipedia
ウィキペディアD言語の記事があります。

D言語はWalter Bright氏によって開発が始められた言語です。


2010年代にFacebook社がD言語を支援したので有名になりましたが、しかしFacebook開発ではなくWalter Bridge氏の開発する言語であり、2001年からD言語は公開されています。

なお、Walter Bright氏は、低価格/高速コンパイラで名を馳せた Datalight C、世界初のnative-C++コンパイラ Zortech C++、そしてその後継であるSymentec C++、Java開発環境 Cafeなどで知られています。

公式名称は「D language」(D言語)または「D programming language」ですが、英語ではネット検索などの利便性のため "dlang" と表記される場合もあります。

目次

D言語の特徴

D言語はC++とは違い、C言語とのソースの互換性はありません(C言語のライブラリとは互換性あり)。もし互換してしまうと古い時代遅れのノウハウ(バッドノウハウ)を引きずりかねない、と考えていたためです。

D言語はシステムプログラミング言語を目指しています。システムプログラミング言語とは、オペレーティングシステムそのものの開発もでき、高速で動く言語のことです。(たとえばC言語はシステムプログラミング言語です。LinuxはC言語で書かれています。)

実際にD言語で開発されたOSが市販や公開されているかはともかく、D言語がOS開発言語も目指していることは、利用上、とても重要です。なぜなら、ユーザーにとって手間が掛かるかもしれないが、とりあえず、今までC言語で出来たハードウェア制御は、D言語でもひととおり出来るようになる予定・目標だからです。


D言語の特徴をいくつか上げておきましょう。

  • ネイティブな形式にコンパイルされるため動作が速い - JavaやRubyなどのインタプリタや仮想機械上で動作する言語に比べて非常に高速です。
  • C言語・Javaと似ているため、学習コストが低い
  • 自動メモリ管理 - ガベージコレクタを搭載しているため、メモリの取得・開放に関してプログラマが気にする必要はありません。もちろん手動でメモリを管理する方法も用意されています。
  • 保守性 - assert、unittest、invariant、debug, version による条件コンパイルなど、プログラムの保守性を高めるための機能があります。また、関数に定められる@safeなどのセキュリティレベルも保守性に貢献するかもしれません。
  • 可読性の高いテンプレート - C++と比べてテンプレートの構文がすっきりしていて仕様を把握するのも簡単です。
  • 強力なCTFE(コンパイル時関数実行) - D言語はかなりの範囲の関数の結果等をコンパイル時に実行することができます。
  • 豊富な表現力 - 関数型言語やオブジェクト指向言語といったパラダイムを非常にうまい具合に言語に組み込み、高い水準で両立させています。今後、借用(@live)に関連する機能も充実化される予定です。
  • コンパイルの速さ、コンパイラの開発しやすさ - D言語はそのコンパイラの開発が簡単になるように設計されており、特にパースはC++とは比べ物にならない速さです。

上記のうち、C++ との共通点は、ネイティブコンパイルされることくらいでしょう。文法からもわかりますが、D言語はC言語とのメモリ構造が同じになるように設計されており、C言語のライブラリを使えるようになっています。一方で、C言語の printf のような古い関数は D言語では writef を使ったり、ファイル入出力のためのクラス File があったりなど、D言語のより型安全で抽象的にラップされた機能があります。

C++ と違って cout の後ろの << の方向が >> だったかそれとも << だったかで悩む必要もD言語では無く、直感的にD言語は扱いやすく設計されています。

C++ や他言語との重要な違いはテンプレートです。テンプレート引数を < > で表すと、構文解析の際にそれがテンプレートの引数なのかそれとも比較式なのかを、記号表をいちいちチェックしなければならず、パースの時間が非常に長くなってしまいます。D言語は ! が二項演算子として使われていないことに着目して、これをきれいに解決しました。

Hello World!

まずは環境がちゃんと動くか試してみましょう。例として、"Hello World!"という文字列を表示させるプログラムを作ってみることにします。テキストファイルを新しく作り、hello.dという名前にしたらテキストエディタで以下のように編集します。

hello.d
import std.stdio;

void main()
{
    writeln("Hello World!");
}

さぁ、これを動かしてみましょう。

$ rdmd hello.d
$ Hello World!

動きましたか?

正常に動いた場合、コンソール画面に

Hello World!

と文字列が表示されます。

動かなかったのなら、環境変数などをもう一度、確認してみてください。

ソースコードの解説

C言語を知っている読者には馴染みの深い見た目ではあると思うが、初心者向けにコードを一行ずつ解説していくことにしましょう。

import std.stdio;
C言語のコード冒頭によくある#include <stdio.h>に相当する部分ですが、しかしD言語では仕様の細部が違い、D言語にはプリプロセッサはありません。このコードの意味は「stdというフォルダにあるstdioというモジュールをインポートする」という意味です。
さらに意味のわからない単語が出てきましたね。一つずつ解説していきましょう。
std というフォルダや stdio.d というファイルを作った覚えはないと思います。これらはphobosという標準ライブラリと呼ばれるもので、コンパイラのインストール時に一緒にインストールされたものです。おそらく探せば phobos というフォルダが見つかるのではないでしょうか。
stdio.d にどのような内容が書かれているのか気になる方は、直接覗いてみるのも良いでしょうが、ここに定義の一覧が載っていますので、こちらを見るほうが良いでしょう。
「モジュール」という言葉について。D言語では「ソースコードが書かれた一つのファイル」のことを指します。
「インポート」とは、そのモジュール(この場合はstd.stdio)に書かれているシンボルの定義全て(シンボル表)を今のモジュール(この場合はhello.d)から使えるようにする、という意味です。5行目に "writeln" というのがありますね。"writeln" は std.stdio で定義されているのです。
void main()
関数 main を定義するぞ、という宣言です。詳しくは D言語/関数 を参照してください。関数というのは手続きをまとめたもので、値を返したり返さなかったりするもの、という理解で良いでしょう。void は「何も返さない」という意味です。--- 細かいことを言えば、main 関数だけは若干違っており、void main は、int main に内部的に書き換えられ、最後に必ず return 0; をするような仕様になっています。 ---
D言語のプログラムのエントリーポイントは必ず main 関数です。D言語ではC言語と同じように、地の文に直接処理を書き込むことはできません。しかしそうするとプログラムの実行を指定できないため、プログラムが起動されるときは main 関数を呼ぶ、と決まっているのです。
{
D言語では、{ } で囲まれた文のことを「ブロック」、「スコープ」と呼び、そこには文を書き並べることができます。このブロックは関数mainに属し、この関数の処理を表しています。
writeln ( "Hello World!" );
"Hello World!" については説明の必要がないでしょう。ここにある内容が表示されているのです。D言語では文字列を表す方法はたくさんありますが、とりあえずダブルクオーテーション " ... " で囲むことを覚えておけば良いでしょう。
writeln は関数です。std.stdio というモジュールに定義されているのでしたね。不正確になることを恐れずに言えば、これはターミナルに文字を表示するための関数です。
関数を呼び出すには、関数名の後にカッコで引数をくくる必要があります。この一文は、writeln という関数に引数として "Hello World!" という文字列を与えて、関数を呼び出しているのです。
; は、必ず文末につけなければなりません。
}
4行目の { に対応する閉じカッコです。

D言語の文法

この節では、D言語のプログラムがどういう見た目をしているか、その全体像をまとめたものが書かれています。それぞれについてもう少し詳しく書かれたものはもっと下の節にありますので、そちらを参照してください。

ここ以外にも、D言語ツアーを読むと良いかもしれません。D言語ツアーは初心者向けの公式ガイドの和訳です。

概観

D言語の構文はC言語やJavaに似ており、テキストに書かれたプログラムを1行ずつ処理していく手続き型言語の側面を持ち合わせています。基本的な流れや、一つ一つの文、コメント、演算子などもC言語を元にしています。詳しくはC言語の該当項目を参照してください。

ここでは、D言語の文法について事細かに説明することはしません。ただしC言語と異なる部分もあるため、その部分については必ず明記しています。

コメント

D言語のコメントは三種類あります。

  • // 一行コメント
  • /* 複数行コメント */
  • /+ ネスト /+ コメント +/ +/

変数宣言

関数宣言

D言語は強い静的型付け言語です。型とはデータの種類を表すものであり、典型的なものとして、int型, float型、string型、配列型、ポインタ型、関数型、といったものがあります。D言語は静的型付け、つまりコンパイル時に変数の型が必ず決まるのです。このように聞くとなんだか難しい気もしますが、D言語には強力な型推論の機能があり、厳格に気にしなければならないわけではないことは、変数宣言のセクションを見ればわかるでしょう。

C言語を知っている人へ : C言語での型のコードがD言語でエラーなくコンパイルされるなら、双方で同じ解釈をされます。

プリミティブな型

プリミティブな型、つまりそれ以上分解できない型を以下に挙げます。

整数型
  • byte 符号付き8bit整数
  • ubyte 符号無し8bit整数
  • short 符号付き16bit整数
  • ushort 符号無し16bit整数
  • int 符号付き32bit整数
  • uint 符号無し32bit整数
  • long 符号付き64bit整数
  • ulong 符号無し64bit整数
  • cent 符号付き128bit整数 (現在は使用不可)
  • ucent 符号無し128bit整数 (現在は使用不可)
浮動小数点数型
  • float 32bit
  • double 64bit
  • real x86 CPUでは80bit、それ外は double と同じ
文字型
  • char 符号無し8bit UTF-8 コードユニット
  • wchar 符号無し16bit UTF-16 コードユニット
  • dchar 符号無し32bit UTF-32 コードユニット
その他の型
  • void 「値が無い」ことを示す型。
  • bool 真理値 true false を表す型。
  • size_t 符号付き整数型。最大値まででプログラムのあらゆるメモリにアクセスできるように保証されている。通常は ulong を指す。
  • ptrdiff_t 符号無しの size_t

型を表示するには

typeid を使って型を表示することができます。以下の例1を見てください。

例1

import std.stdio;

void main()
{
    int   a = 42;
    float b = 32.5f;
    writeln(a, " ", b);     // 42 32.5
    long  c = 16;
    ulong d = 26;
    bool  e = a == c+d;
    writeln(e);             // true
    writeln(typeid(a-c-d)); // ulong
}

異なる型の間の演算、型キャスト等についてはD言語/型を参照してください。

配列型・ポインタ型

T に対して T[] という型が存在します。これは「Tの動的配列型」であり、参照型です。配列型の変数は、内部的にはヒープ領域にあるデータの先頭を指すポインタと配列の長さを持っています。これはC言語の配列のバッファオーバランを実行時エラーとするという改善です。

配列の長さは、length というプロパティで取得することができ、length プロパティにsize_tの値代入するとその長さの配列をメモリに確保してくれます。なお、確保されたメモリの各要素は、その型の初期値で初期化されます。

C言語経験者向けの注意 : Cスタイルの宣言 int array[]; は許可されていません。

例2

import std.stdio;

void main()
{
    int[] a = [2, 3, 5, 7, 11, 13];
    writeln(a, " ", a.length);    // [2, 3, 5, 7, 11, 13] 6
    
    auto b = a[0 .. $-2];    // $ は [ ] 内で使われると、その配列の長さ length を指す
    b[0] = 20;
    writeln(b, " ", b.length);    // [20, 3, 5, 7] 4
    writeln(a);    // [20, 3, 5, 7, 11, 13] (a, b は同じメモリ領域を指すため、b の要素を書き換えると a も変化する
    
    auto c = a ~ [17, 19];    // 連結 ~ によってヒープ領域に新しい動的配列が確保され、c はそれを指すようになる
    wirteln(c);    // [20, 3, 5, 7, 11, 13, 17, 19]
    c[1] = 30;
    writeln(c);    // [20, 30, 5, 7, 11, 13, 17, 19]
    writeln(a);    // [20, 3, 5, 7, 11, 13] (c は a のコピーを連結したので、a と同じ場所は指さない
}

例3

import std.stdio;

void main()
{
    int[] a;
    a.length = 10;
    writeln(a);    // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    
    auto b = new int[10];    // これでも長さ10の配列を確保できる
}

連想配列型

function / delegate 型

制御文

if 文

while 文

do-while 文

for 文

goto 文

switch 文

foreach / foreach_reverse 文

その他の文

ブロック文

with 文

asm 文

mixin 文

assert 文

ユーザー定義型

enum

struct

class

クラスは複数の変数を一まとめにし、それらを扱う関数も内包することで、簡潔で他のプログラムに依存しない独立した処理を可能とします。また、クラスは雛形(ひながた)であり、同じ性質を持ったデータ(オブジェクト)を多数作る事ができます。

実体化

クラスは雛形に過ぎないため、実際に変数として使うためには定義、宣言した後に実体化(インスタンス化)という作業が必要になります。Cというクラスのオブジェクトc1は

C c1;    // 宣言
c1 = new C();

で実体化できます。これ以降c1をC型の変数として扱う事ができます。newが実体化する命令で、その対象はCというクラス、という事です。空白の()は後述するコンストラクタに何も指定しない事を意味します。

メンバ変数

classの中に定義された変数の事を特にメンバ変数と言います。 オブジェクトの持つデータそのもので、これを扱いやすくするための仕組みが以下になります。

メンバ関数

classの中に定義された関数を特にメンバ関数と言います。 メンバ変数に対する決まりきった処理を他のオブジェクトに依存すると、関わるオブジェクト数が増えるため複雑で読みにくく直しにくいコードになります。メンバ変数の事はメンバ関数に任せましょう。

コンストラクタ

this()という名前を持つ特殊なメンバ関数です。クラスをオブジェクトとして実体化する際に、this関数の中で定義された初期化処理を実行します。引数なしの場合はメンバ変数のデフォルト値を与えるのに使います。初期化するだけなので、返り値はありません。

this()
{
    i = 0;
    str = "Default string";
}

引数ありの場合も定義でき、何個でも定義できます(オーバーライド)

this(int x)
{
    i = x;
    str = "int override";
}
this(string strin)
{
    i = 0;
    str = strin.idup;
}

ここで定義した関数は、new実行時にC(引数)と表記する事で、引数に応じてthis(引数)関数を実行します。様々な初期状態を持った同じクラスのオブジェクトを作るのに便利です。

演算子オーバーロード

四則演算(+-*/)など多くの演算記号を、クラスに対してまるごと作用させる演算を定義できます。

union

例外処理

契約

参考文献

  • プログラミング言語D Andrei Alexandrescu著 長尾高弘訳 株式会社翔泳社出版 ISBN 978-4-7981-3110-8
  • Programming in D Ali Çehreli著 ISBNs 978-0-692-59943-3 978-0-692-52957-7 978-1-515-07460-1 978-1-515-07460-1

外部リンク

このページ「D言語」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。