Contents

  • Hello, world!---その前に
  • Hello, world!
    • 注意...
  • Hello, world!を詳しくみてみる
    • 注意...
    • 1行目
    • 2行目
    • 3行目
    • 4行目
    • 5行目
    • 6行目
  • プログラミング言語の学び方について
  • ファイル名について
  • write, writelnと型について
  • 関数について
  • writef, writefln
  • コメント
  • 問題 -> 解答
  • おわりに
  • キーワード

Hello, world!---その前に

プログラミングの入門といえばHello, world!ですね。 早速書いてみたいのですが、皆さんは コンパイラテキストエディタ は手に入れていますか?

プログラム(==ソースコード)を書くには、テキストエディタがいります。 notepad.exeで編集したければそれでいいのですが、せっかくなのでカッコイイテキストエディタを入手しましょう。 各エディタの説明はしませんが、個人的にはSublime Text3がオススメです。

  • Sublime Text3
  • notepad++
  • Vim
  • Emacs

エディタをゲットしたら、次はコンパイラを持ってこないといけません。 D言語のコンパイラは有名なもので dmd, gdc, ldc などがありますが、普通は dmd を使うのでここからダウンロードしましょう。 Windowsの人は"dmd Windows installer"をダウンロードして実行すれば全部設定してくれます。

インストールが終われば、コンソール(ターミナル)画面をたちあげてdmdと打ちましょう。 ズラズラズラ~と文字が出てきたら成功です。

Hello, world!

さて、テキストエディタを立ち上げて以下の文字列をそのまま打ち込んでhelloworld.dで保存しましょう。

import std.stdio;

void main()
{
    writeln("Hello, world!");
}

次にコンソールで以下をタイプします。 $ から始まる1行はコンソールへの入力を表しますが、$はわざわざ打たなくて結構です。 なので、$以降のrdmd ~を打ち込みましょう。

(rdmdが見つからないとエラーが出たらdmd -runを使ってみてください。)

$ rdmd helloworld.d

コンソールで以下のように出力されれば成功です、おめでとう!

Hello, world!

注意...

これからはrdmd ...などのコマンドと実行結果を一緒に、以下のように表記します。

$ rdmd helloworld.d
Hello World!

Hello, world!を詳しくみてみる

先ほど書いたHello Worldプログラムを解析してみましょう。

注意...

ここから先はいきなり意味がわからない単語が急増します。 しかし、後から詳しく説明しますので、難しければ素直に読み飛ばしましょう。 そのうち分かるようになるので、「もうだめぽ」とか「やっぱり自分には向いてない」とか思わないように。 執筆者も「これはまだ分からなくていい内容だわ」と割りきって書いています。

1行目

import std.stdio;

「モジュールstd.stdioを読み込む」という意味です。 std.stdiostdはstandardの略で、stdioはstandard Input/Outputの略です。 なのでstd.stdioというのは、「stdパッケージに属するstdioモジュール」という意味です。 これについては、モジュールの章で説明します。

なぜこのような記述をしなければいけないかというと、5行目で出てくるwritelnをプログラム中で使いたいからです。 writelnstd.stdioで定義されているのですが、自分のプログラムにimport(輸入)してやらなければ使えません。 つまり、「barモジュールで定義されてるfooを使いたい!」という場合には、import bar;と書かなければいけません。

また、;という記号が至るところで出現します。 今のところは、「この記号はなんか必要なんだな」と思ってしまってください。

2行目

2行目はただの空白です。 D言語のプログラムのソースコード中では、 任意の場所に空白や改行を入れても構いません 。 もちろん、importi m p o r tと書いてはいけません。

3行目

void main()

D言語で書かれたプログラムは、 main という関数(function)から始まります。 プログラムでの関数は数学の関数とほとんど同じで、入力(input)を受け取り、加工や外界に影響を及ぼしてから出力(output)を返すものです。 このmainの場合は何も受け取らずなにも返しません(void)が、void main(string[] args)と書けば、string[] argsを受け取ってなにも返さないmain関数となります。

一般的な関数はソースコード上では以下のように記述されます。

OutputType fName(InputType1 arg1, InputType2 arg2, ...)
{
    function Body
}

OutputTypeは関数の出力の型(タイプ)、InputType1とかInputType2は入力の型(タイプ)で、arg1, arg2は仮引数(かりひきすう)と呼ばれます また、InputType1, InputType2は引数の型, OutputTypeは返り値や戻り値の型(Returned Type)と呼ばれます。 function Bodyは関数本体といい、入力から出力を生成する手順を記述します。

  • ちょっと休憩

さて、難解になってきました! C言語などの他の言語をちょっとでも触ったことのある人であれば大丈夫かもしれませんが、 まったくの初心者がこの文章を理解できていれば、その人は間違いなく「真のプログラマの生まれ変わり」です! もちろん、このd-manualはそんな伝説を対象にD言語を紹介しているわけではありませんから、普通の初心者の方はなんとなく目で追うだけでいいのです。 再度言いますが、私も初心者をいきなりつまずかせて楽しむ鬼ではありません。 理解できたら異常なのです。

対して、他の言語の経験者の方は多分大丈夫だと思いますが、もし理解が怪しかったとしても読み進めることを諦めないでください。

4行目

{

3行目の項で説明した関数の{}のうちの開始の括弧です。 ここから6行目の}までは関数本体となります。

5行目

    writeln("Hello, world!");

この行は、「writelnという関数に"Hello, world!"を引数として渡して、呼び出す」という意味です。 writelnという関数はstd.stdioにあるというのは説明しましたね。

writelnは、"write", "ln"に分解できます。 "write"は書きだす、"ln"は改行を意味します。 つまり、writeln("Hello, world!")は「"Hello, world!"と書きだして改行する」という意味です。

writelnがあるんだから、writeもあります。 writeは改行なしで出力すること以外はwritelnと同じ動作です。 write, writelnについて後ほど詳しく説明します。

6行目

}

main関数の終了を表す括弧です。 D言語のソースコードでは、括弧は必ず対になっていなければなりません。

プログラミング言語の学び方について

さて、なんとかここまでたどり着いた人たちはおめでとうございます。 ここから先は、ここに載っているプログラムを写経してもらうことが重要になります。 写経をなめてはいけません。 サンプルのプログラムを目で追うだけでは、そのサンプルに秘められた重大な意味を理解できません。 写経し、説明文を読み、そのサンプルを理解することが重要です。

しかしながらこの章は導入でしかないので、写経をしてもその意味の理解をしなくても大丈夫です。 後々の章でじっくりと煮詰めるので、むしろそれまで楽しみにしておいてください。

ではこの章の後半、D言語の摩訶不思議な世界をご堪能ください。

ファイル名について

おっと、いい忘れていたことがありました。 サンプルのプログラムの写経を保存するファイルの名前ですが、はっきり言うと何でもいいですが、次の規則に従うように心がけてください。

  • 拡張子は.d
  • 数字から始めない
    • 0foo.dはダメ
  • 数字やアルファベット以外の文字は入れない
    • a-b.dなんかはダメ

write, writelnと型について

Hello, Worldと名前がついたサンプルコードで出てきたwrite, writelnstd.stdioで宣言(==定義)されています。 writewritelnは複数の引数を受け取ることができます。 つまり、先ほどのHello, worldのプログラムを改変した以下のコードも有効です。 コンパイルして実行してみましょう。

import std.stdio;

void main()
{
    writeln("Hello, ", "World! ", 123);
}
$ rdmd helloworld.d
Hello, World! 123

さて、"Hello, ""World! """ でくくりましたが、123""でくくってません。 というのは、""でくくったものは string(文字列) という型になるのに対し、123とそのまま書くと int(整数) という型になります。

ほとんどのプログラミング言語は、データに を持ちます。 ここでいうデータというのは、"Hello, "とか123とかのことで、型というのはstring, intのことです。 もしデータに型がなければどうなるでしょうか? コンピュータは0, 1で全てを表しているといいますが、123"Hello, "01で表されてしまいますから、文字なのか数値なのかよくかわらなくなってしまいます。 そのようなことを避けるために、数値にはint, 文字列にはstringと型を付けるのです。 そして、writelnはどんな型が入力に入っているかを確認できるので、それぞれの型に合わせて出力のフォーマットを変えてくれます。

関数について

型についてちょっとはわかったと思うので、次は 関数 について少し理解しましょう。 プログラムは関数とデータの集合だと考えることができます。 「関数にデータを渡して、関数がデータを処理してなにか値を返す」というのがプログラムの流れです。 関数中では、原則上から順番に文が実行されていきます

import std.stdio;

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

上のコードを実行しても、一つ前のものと同じ表示になります。 もし、関数内の実行手順が上から下でないなら、ぐちゃくちゃになっているはずです。

main関数以外の関数を定義して呼び出すことも可能です。 以下のコードでは何もしない関数fooを定義してmain関数から呼び出しています。

void main()
{
    foo();
}


void foo(){}

fooの位置は重要でなくて、たとえばmain関数の上に書いても大丈夫です。

void foo(){}

void main()
{
    foo();
}

fooを2回呼び出すことも可能です。

void foo(){}

void main()
{
    foo();
    foo();
}

writef, writefln

C言語を勉強した人は、一度はprintfを使ったことがありますね。 D言語にもprintfのようにフォーマットを指定して数値などを出力できるwritef, writeflnがあります。

import std.stdio;

void main()
{
    writefln("%d : %d", 1, 2);
    writefln("%s : %s", 2, 4);
}
$ rdmd helloworld.d
1 : 2
2 : 4

一番最初の%dと書いた部分に1が入り、次の%dには2が入っていることが実行結果からわかりますね。 次の行では2つの%sにそれぞれ2, 4が入っています。 %d%sはフォーマット指定子といい、%dは10進数出力を表します。 %sはデフォルトの指定子で、この場合は%dに等しくなります。

もし数値を16進数で出力したい場合には%x, %Xを使います。 %xは小文字、%Xは大文字で出力します。

import std.stdio;

void main()
{
    writefln("%x : %X", 200, 200);
}
$ rdmd helloworld.d
c8 : C8

もし、文字列を出力したいなら%sを使います。

import std.stdio;

void main()
{
    writefln("%s", "これは文字列");
}
$ rdmd helloworld.d
これは文字列

%d%xで文字列を出力しようとした場合にはエラーが出ます。

import std.stdio;

void main()
{
    writefln("%d", "これは文字列");
}
$ rdmd helloworld.d
object.Exception@C:\D\dmd2\src\phobos\std\format.d(2154): Incorrect format specifier for range: %d
----------------
0x00416574
0x004163FF
0x0040466A
0x00404206
0x0040416F
0x004029C1
0x004025F8
0x0040256A
0x00412078
0x0040E329
0x0040B3C0
0x75A833AA in BaseThreadInitThunk
0x77DD9EF2 in RtlInitializeExceptionChain
0x77DD9EC5 in RtlInitializeExceptionChain

指定子がわからなかった場合には%sとしておけば最適なフォーマットで出力されるので便利ですね。

コメント

たとえば、あなたが高度な技術を使用した複雑なプログラムを書いたとしましょう。 そのプログラムにバグがあることが、1週間後に判明しました。 さて、あなたはプログラムのバグを取り払うことができるでしょうか?

このような状況にされされた場合、ソースコードを読み解く必要があるのですが、コメントを残しておくことでソースコードの可読性が向上します。 たとえば、「ここではhogehogeをfugafugaしている」などです。 よいコメントを書けるプログラマはよいプログラマになれます(たぶん)。

//std.stdioを読み込む
import stds.stdio;

/** main関数
 * Hello, World!と出力
 */
void main()
{
    /+
    writeln("fugafuga");
        /+
        writeln("なんだと…");
        +/
    writeln("hogehoge");
    +/

    writeln("Hello, World!");
}


/* ネストできないコメント
ここはコメント
    /*
    ここはコメント
    */
ここはコメントでない
*/

/+ ネストできるコメント
ここはコメント
    /+
    ここはコメント
    +/
ここはコメント
+/

/** ドキュメント
*/

/++ ネスト可能なドキュメント
+/

// 1行コメント

問題 -> 解答

  • 次のソースコードの<a><b>の部分に適切なものを入れて、Hello, World!と表示するプログラムを作ってください。
import std.stdio;

void main()
{
    writefln("%s, %s", <a>, <b>);
}
  • 次のソースコードは複数箇所間違っています。コンパイルしてエラーを確認しながら、訂正してください。 初心者の方は、一番最初に示したサンプルコードとの差を確認しながら訂正してみてください。
vood main{
    writeln("Hello, World");
}
  • つぎのソースコードをコンパイルして、エラーメッセージを読んでみましょう。プログラミングではエラーメッセージに慣れることが上達するための近道です。
void main(){
    writeln("foo");
}
void main(){
    writeln("foo");
void main{}
main()
main

おわりに

さて、第一回目の「Hello, World!」の項が終わりました。お疲れ様でした。 実は今回はかなり内容が詰まっていて、書いてる途中から「初心者にはつらいかなあ」と思っていました。 プログラムの概念を考えると、今のノイマン型コンピュータを考えるところまで行き着いてしまい、D言語の話になかなか戻ってこれないので、このようなちょっと難しい形式になってしまいました。 このような難しいお話については、C言語の入門書の頭のほうにわかりやすく書かれていることが多いので、図書館へ行って借りることをオススメします。 また、D言語について詳しく知りたいと思った方は、「プログラミング言語D」(The D Programming Language; 略称:TDPL)という本をおすすめします。D言語の文法やそれに至った経緯など、詳しく学ぶにはとっておきです。 ただ、プログラミング初心者向けではなく、ある程度プログラムの知識がないと難しい内容の本です。

キーワード

  • dmd
  • import
  • std.stdio
  • main
  • 関数(function)
  • write, writeln, writef, writefln
  • 型(type)
  • 値(value)
  • 数値(integer, int型)
  • 文字列(string型)
  • フォーマット
  • コメント