今回は、難しいことを考えずに C# のいろいろな機能を試してみましょう。
今回の目標
- 式と文の違いを明確に理解する。
- 様々な種類の式を使ったプログラムを書けるようになる。
- if, for, while などの基本的な制御文を使えるようになる。
メソッドの中身を書いてみよう
今回は、KclcFirst の Main メソッドの中身を書いていきます。
特に断りがない限り、
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace KclcFirst
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 // ここに入る
14 }
15 }
16 }
の // ここに入る
の部分に追記してください。
また、Mono を使っている場合は、csharp
コマンドを使うことで、メソッドの宣言などをせずに使うこともできます。
ここでもう一度基本的な型の種類をおさらいしておきましょう。
- int 型 … 整数型。-2,147,483,648~2,147,483,647 の範囲の数を表せる。
- long 型 … 整数型だが、もっと桁数が多い数を扱える。
- string 型 … 文字列型。
- char 型 … 文字型。string 型は char 型の配列である。(配列については後述)
- float 型 … 実数型。小数点を扱うことができる。 double 型はその名の通り精度が二倍。
- void 型 … 値を持たない。他のメソッドに渡して使うこともできない。
- bool 型 … true(真)かfalse(偽)の2つの値のみを持つ。
いろいろなリテラル
- int 型 … そのまま数字を書く。
- long 型 … 数字の後ろに「l」をつける。
10l
- float 型 … 数字の後ろに「f」をつける。
1.0f
- double 型 … 数字の後ろに「d」をつける。
1.0d
- string 型 … 文字列を
""
の中に入れる。"abc"
- char 型 … 文字を
''
の中に入れる。'a'
- bool 型 …
true
かfalse
long や float などにみられる、数字の後ろにつけることで型を表す文字をサフィックスと言ったりします。
変数を使ってみる
まずは式の一つである「変数」を使ってみましょう。
変数は特殊な式で、他の式の結果を保存しておくことができます。
そのため変数を使うには宣言が必要です。
宣言文
変数を宣言するには「宣言文」を使います。
型の名前 変数名;
と書きます。
もちろん、void 型の変数なんてものを作ることはできません。
実際に、string 型の変数 s を宣言してみましょう。
string s;
はい、簡単ですね。次はこの s に値を保存してみましょう。
変数に値を保存することを「代入」と言い、「代入文」で表します。
代入文
代入文は次のように書きます。
変数名 = 式;
では早速、s に式 Console.ReadLine() の結果を代入してみましょう。
Console.ReadLine() の意味は覚えていますね?そうでなければ前回を参照してください。
s = Console.ReadLine();
はい、これで変数 s にコンソールから入力した文字列が代入されました。最後にこれを表示してみましょう。
Console.WriteLine(s);
これで、入力した文字列がそのまま表示されるはずです。
宣言と代入を一度に行う
宣言と代入を分ける必要がないときは、一緒に書くことができます。
型名 変数名 = 式;
これにより、さっきのコードは次のように書き直せます。
string s = Console.ReadLine();
var を使う
いちいち string とか int とか書くのがめんどくさい!
そんなあなたに、var というものがあります。これは、
var 変数名 = 式;
と書くことにより、右側の式から変数の型が int なのか string なのかその他もろもろなのかを自動で判断します。
つまり、型の名前を書く必要がないのです。
コレを使えば、
var s = Console.ReadLine();
というように書けます。
int とか string とか短い名前の型なら、そのまま書いてもそこまで短くならないのであまりいらないように見えるかもしれません。
しかし、少し高度なプログラムを書くようになると、 Random だとか HttpClient だとか IObservable だとか長い名前の型を使うようになるので、今のうちに習得しておくのをオススメします。
なお、
var 変数名;
ということはできません。右側に式がないので、型が何なのか全然わからないからです。
また、もし変数の型がわからなくなったら、マウスをコード中の変数に重ねてみてください。
上のように、型の名前と変数の名前が出てくるはずです。
型がわからないものは、変数に限らず、上にマウスを重ねてみると型の名前などを見ることができるので有効活用していきましょう。
null
実は C# には、null と呼ばれる特別なリテラルがあります。
これは、文字列やクラス型などにのみ使うことができる、「なにもない」ということを表すリテラルです。
string s = null;
実は C# の型には「値型」と「参照型」の2種類があり、値型は値をそのままやりとりするのに対し、参照型はデータが存在する場所をやりとりします。
値型は int や long、double など、参照型は string やクラス型などです。
値型が現金取引なら、参照型は「ここに金を隠した」という紙をやりとりするのに似ています。
それで、参照型の値には「どこにも金がない」という状態があり、それが null なのです。
詳しい話をすると C# の内部実装の話になってしまうので、「数には null を使えない」と覚えておけばOKです。
変数を初期化しなかった場合、値型の場合は0、参照型の場合は null が入っています。
また、default
という命令を使うと、その型のデフォルトの値を手に入れることができます。
これを試してみましょう。
int hoge = default(int);
string fuga = default(string);
Console.WriteLine(hoge);
Console.WriteLine(fuga);
演算子を使ってみる
演算子とは、数式でいう + や - などに相当し、そのまま同じような書き方をすることができます。
すべての型で使える演算子(抜粋)
==
… 2つの値が等しいかどうかを bool 型で返す。1 == 1
!=
… 2つの値が等しくないときに true を返す。1 != 2
整数型・実数型に使える演算子(抜粋)
これらの演算子は、int や long、float、double などの数を表す型に対して使うことができます。
+
… 数字を足して同じ型で返す。1 + 1
-
… 数字を引いて同じ型で返す。1 - 1
*
… 数字を掛けて同じ型で返す。1 * 1
/
… 数字を割って同じ型で返す。1 / 1
%
… 数字を割った余りを返す。6 % 4
<
… 左の数のほうが大きいかどうかを bool 型で返す。2 > 1
>
…<
の逆。2 < 1
<=
,>=
…<
,>
の、等しい場合も真とするバージョン。以上・以下に相当。
文字列に使える演算子(抜粋)
+
… 文字列同士を連結する。"a" + "b"
bool 型に使える演算子(抜粋)
!
… 条件をひっくり返す。true なら false、false なら true になる。!true
||
… どちらかが true の時に true を返し、どちらも false なら false を返す。「OR演算子」とも言う。true || false
&&
… 両方 true の時だけ true を返し、どちらかが false なら false を返す。「AND演算子」とも言う。true && false
代入を一度にする演算子
+
や -
などの演算子は、=
を後につけることで、「その操作を行いつつ代入」という意味になります。
具体的には、
i = i + 1;
と、
i += 1;
は同じ意味です。
インクリメント・デクリメント
i = i + 1
や i = i - 1
というような式に関しては、「インクリメント演算子」と「デクリメント演算子」を使うことで、もっと短く書くことができます。
同じ意味:
i = i + 1;
i++;
++i;
i = i - 1;
i--;
--i;
ただ注意しておきたいのは、i++
と ++i
は挙動が違います。
i++
は式としては i をそのまま返すのに対し、++i
は i に 1 を足した結果を返します。
要するに、var j = i++;
とすると j は「現在のi」より 1 少ない数となりますが、var j = ++1;
とすると j は「現在のi」と等しくなります。
これはこんがらがると大変なことになるので、どちらか合う方だけを使うようにしましょう。
初期化式を使ってみる
初期化式は、クラスから「インスタンス」と呼ばれるものを作る式です。
クラスを作るのは結構理解が難しいので、今回はすでにあるクラスを使ってみましょう。
今回は、 System 名前空間にある Random クラス(乱数を生成する)を使います。
インスタンスって何かって?まぁまぁ、とりあえず細かいことを考えずに使ってみましょう。
初期化する
初期化式は次のように書きます。
new クラス名();
// 初期化に値が必要な場合
new クラス名(値);
さて、Random クラスのインスタンスを2つ作って、変数に代入してみましょう。
Random クラスは「シード」という、乱数の元となる値を設定することができます。
random1 はシードを 123
、random2 は 456
にしてみましょう。
var random1 = new Random(123);
var random2 = new Random(456);
これで Random 型の変数 random1 と random2 が用意できました。
このように、クラスはそれ自身を表す型を持ち、int などと区別してクラス型と呼ばれます。
メンバーメソッドを使う
さて、実際に random1 を使って乱数を取得してみましょう。これには、Next メソッドを使います。
Console.WriteLine(random1.Next());
この .Next() の . (ドット)は、Console.WriteLine のドットと同じ意味で、クラスに含まれるメソッドを指すときに使われます。
この、クラスに含まれているメソッドのことを「メンバーメソッド」と言います。
同じように、クラスは変数やプロパティ(変数と似たものです。オブジェクト指向編で解説します)を含むことができます。
これらも同様に、メンバー変数やメンバープロパティなどと言います。
Visual Studio でも MonoDevelop でも、ドットを打った瞬間にそのクラスが持つメンバーがズラーっと候補として表示されるはずです。
さて、出力を見てみましょう。
1589351479
全くのデタラメですね。あなたの画面には確実にここに書いてあるのと違う数字が出ているはずです。
さて、 random2 でも同じように乱数を取得してみましょう。
同時にインスタンスを生成したので、同じ値が出てきそうなものですが…
Console.WriteLine(random2.Next());
僕のパソコンでは、今度は
636837953
と出ました。全然違うじゃないか!
そうです。これがまさしく「インスタンス」の特徴なのです。
1 と 1 は式として完全に等しいですが、random1 と random2 は全くの別物なのです。
つまり、「初期化式」はクラスを設計図として新しい製品をポンっと作り出すようなものなのです。
大量生産された目覚まし時計はそれぞれ同じ機能を持ちますが、内部には違う設定時間などを持たせることができます。
このように、ひとつのクラスから、細部が違うたくさんのインスタンスを作ることができるのです。
配列(array)を使う
そろそろあなたのコードは変数だらけになってきたことでしょう。
複数の変数を一つにまとめる方法はないの…?
あります。それが「配列型」です。配列とは、複数の同じ型の値を収納しておけるものです。
配列型
配列型はクラス型とかなり似ていて、それぞれが違う値を持てるところも、初期化の仕方も似ています。
配列型の宣言はこう書きます。
型の名前[] 変数の名前;
配列型の初期化式はこうです。
new 型の名前[配列の長さ];
配列の長さは初期化の時に指定する必要があります。
使ってみよう
例えば、int 型の値を5個収納できる配列を作るには、
var a = new int[5];
とします。
配列の要素にアクセスするには、変数の後に [] をつけ、中に何番目の値を読み書きするかを書きます(インデックスと言います)。
a[2] = 1;
これで配列型の変数 a の2番目の要素に 1 が代入されました。
このまま表示することもできます。普通の int 型の変数と同じように扱えることがわかるでしょう。
Console.WriteLine(a[2]);
ここで注意しておきたいのは、配列のインデックスは 0 から始まります。
プログラマーは数は0から数える習性があり、C# もその伝統に則っています。
つまり、a に a[5] は存在しません。 a[4] が最後の要素です。
特別な初期化式
配列を初期化したあとにいちいち代入するのはめんどくさいので、特別な初期化式を使うことができます。
new 型の名前[]{ 値1, 値2, 値3, ... }
これを使って a の初期化式を書き換えてみましょう。
var a = new int[]{1 ,2, 3, 4, 5};
これで、a[0] には 1、a[1] には 2 … という具合で最初から値がセットされます。
配列型の変数は、型の名前[] 型の変数として扱われます。
つまり、違う型の配列を代入したり、配列に違う方の値を入れることはできません。
試しに a の上にマウスを重ねてみて、型がどのように表示されるか見てみましょう。
二次元配列
この表のように、縦のインデックスと横のインデックスの2つを使ってアクセスすることができる配列型があります。
2つ方法があり、二次元配列専用の型を使う方法と、配列の配列を作る方法があります。
二次元配列型
インデックスを「,」で区切って2つ使う以外は、普通の配列と同じです。
二次元配列の宣言はこう書きます。
型の名前[,] 変数の名前;
初期化はこうです。
new 型の名前[縦の長さ, 横の長さ];
実際に使ってみましょう。
var b = new int[2, 2];
b[0,1] = 10;
二次元配列型の特別な初期化式は、{} が一段階増えるだけです。
var c = new int[,]{ {1, 2}, {3, 4} }
Console.WriteLine(c[1, 0]);
ジャグ配列
ジャグ配列は、配列の中に配列を並べる方法です。
実際に配列の配列を作ってみましょう。
var d = new int[2][];
d[0] = new int[3];
d[1] = new int[4];
d[0][2] = 10;
d は int[] 型の配列になりました。
d[0] には長さ 3 の、d[1] には長さ 4 の配列が入りました。
このように、要素のそれぞれに対して初期化をしなければならないのがジャグ配列の面倒なところです。
配列は初期化されなければ null のままで使うことができないのです。
もちろん、こう書くこともできます。
var e = new int[2][]{ new int[3]{ 1, 2, 3 }, new int[4]{ 4, 5, 6, 7 } };
Console.WriteLine(e[1][0]);
どちらを使うべきか?
二次元配列は書きやすく初期化も簡単です。それに対してジャグ配列は初期化が面倒です。
しかし、ジャグ配列には、各行の長さを変えることができ、各行を一次元配列として返すことができる、という大きな利点があります。
場合場合によって使い分けていくしかないですし、どのような場合にどちらが使いやすいかは自分で見つけていきましょう。
多次元配列
二次元配列型の , の数を増やしてみたり、ジャグ配列を宣言するときに[]に数を増やしたりしてみましょう。
次元はいくらでも増やすことができます。いろいろ試してみましょう。
続く
「C# の基本的な使い方2」 に続きます。