変数の特徴
一般的な言語ではプリミティブ型と分類される基本的な型が存在します。しかし、Dartでの変数の型はすべてがオブジェクト型の派生タイプであり、基本ライブラリで型が用意されています。
そのため、厳密な基本型という定義があるわけではありませんが、その他の言語で基本的な型に相当するもののみを表1に示しました。Stringについては、他の言語によっては基本型とは区分されていないものもあります。しかし、DartではこのString以外に文字列を扱うための型が無いために、基本型として紹介しています。
| 型 | 概要 |
|---|---|
| int | 整数。64bitで管理された整数になります。ただし、Flutter内で使う場合には64bitでの整数ですが、他の実行環境の場合には異なるので注意が必要です。 |
| double | 浮動小数点数。 |
| num | intとdoubleの親タイプとなる型。 |
| bool | 論理値。trueもしくはfalseの値を取ることができます。 |
| Null | null値の型。 |
| String | 文字列型。Dartでは、Javaなどで存在するcharといった1文字を扱う型はありません。 |
またbyteなどの型も無いので、int型などで代用することになります。
型変換
型変換をする場合には、それぞれのクラスに変換メソッドがあるので、そちらを利用します。例えば、小数点まで管理できるdouble型を、整数型(int)に変換する際には、toIntのようなメソッドを利用します。
double num = 10.5; int intNum = num.toInt(); // 10になる
変数の自動型推論
変数に型制限があると型を毎回指定する面倒がでてしまいます。一方、このような制限があることで、他人が記述したプログラムがわかりやすく、間違いが起きにくくなるというメリットがあります。
そこで最近の言語では、型を決めつつ記述を簡単にするために、型が自動的に決まる場合は省略できるようになっています。この機能を「型推論」と言います。Dartでも同じように型推論があります。リスト4のように型を指定する代わりに、varキーワードを使うことで省略が可能です。
var num1 = 10; // int num1 = 10;と同じ var num2 = 10.0; // double num2 = 10.0;と同じ
型推論を使うとわかりにくくなるケースもあります。そのような例がリスト5です。
var num3 = 12; var num4 = 3; var num5 = num3 / num4; // (1)型推論を使ってdouble型の3.0の値を設定する double num6 = num3 / num4; // (2)型指定を使ってdouble型の3.0の値を設定する
int型の同士の割り算では、結果はdoubleになります。しかし、(1)の書き方では型が少々わかりにくくなります。この場合には、型推論を使わず、(2)のように明示的に型を指定したほうがよいでしょう。なお、3.0ではなく、3という整数型として扱いたいという場合もあります。その場合、double型からint型へ変換が必要です。この変換方法を示したのが、リスト6です。
int num7 = ( num3 / num4 ).truncate().toInt(); // (1)メソッドを使った型変換 int num8 = num3 ~/ num4; // (2)演算子を使って変換
(1)は、小数点以下をtruncateメソッドで削除し、その後toIntにてint型に変換しています。ちなみに、ここでは型変換の例として、(1)のようなコードを書きましたが、除算で整数型の結果を得たいならば、(2)のように「~/」演算子を利用しても構いません。
型を特定しない変数の宣言
型を意識した言語であっても、どうしても型が決められない場合があります。そういった場合に利用できるのが、dynamic型です。例えば、リスト7のように異なる型の値を同じ変数で扱うことができます。
dynamic val; val = "hello"; val = 10;
先ほど紹介したvarを使った型推論を使って、リスト8のように記述できません。これは最初のval変数を指定する際に、"hello"を指定することで文字列型に固定されてしまうためです。
var val = "hello"; val = 10; // エラー
Generic型
型を意識しないような言語において、最もやっかいな問題の1つに、配列などを使って複数の値を格納して管理するケースがあります。例えば、合計値や平均値を計算するための配列であれば、コーディングレベルでは文字列などの追加を禁止したいところです。そのような場合に利用するのが、Generic型です。例えば、リスト9の通りにすることで、リスト配下の要素をint型に限定できます。
Listvalues = []; values.add(10); values.add("ten"); // 文字列の追加はエラー
一方で、型を意識せず値を格納したい場合があります。そういった場合、利用するのが先ほどのdynamicです。また、Generic型の記述は省略することもでできますが、その場合にはdynamicを指定したことと同じ意味になります。
変数宣言キーワード
先ほど変数を利用する場合には、varや型などを指定しましたが、変数にfinalやconstなどのキーワードを指定すると値の変更できなくすることが可能です。これは2つのキーワードは似ていますが、少々意味が異なります。それらの違いの意味を示したのがリスト10です。
import 'dart:math';
int someValue(){
return Random.secure().nextInt(100); // ランダムな値を返す
}
main(){
// (1)変数の内容を書き換えられないように指定
final int data1 = 100;
const int data2 = 100;
// (2)どちらも変更できないので、コンパイル時にエラーになる
data1 = 120;
data2 = 150;
// (3)ランダムな値を初期値として指定
final int data3 = someValue();
// (4)以下はエラーになる
const int data4 = someValue();
}
リスト(1)のようにfinalやconstを使うと、指定した値(例では100)で固定できます。つまり、定数化が可能です。従って、(2)のようにその後、変数の値を変更しようとすると、コンパイル時にエラーになります。Android StudioなどのIDEを使っていれば、コーディング中にエラーがあることがわかります。この使い方ではどちらを使っても同じ効果になります。
(3)のようにある関数を通じて、ランダムな値を設定するようなケースになると、finalとconstの違いが生じます。(3)のようにfinalを使った場合だとエラーになりませんが、(4)のようにconstを使うことはできません。これは、finalとconstで定数として値を固定するタイミングが異なるからです。finalは実行時に値が固定され、constはコンパイル時に値が固定されます。そのため、(4)ではエラーになります。
JavaScriptのようなスクリプト言語では通常、実行時とコンパイル時を意識することが無いので、この部分も細かい違いですが、わからないと悩んでしまいます。
クラス名の変数名の命名規則
これまでのコードなどを眺めていれば気がつく方もいるかと思いますが、クラス名はUpperCamelCaseというルールで定義されることが望ましいとされています。
これは、大文字で複数の単語をつなげて名称を作るというルールです。ただし、前述した基本的な型で紹介したクラスの中にはこのルールではないものも存在します。また、変数名はlowerCamelCaseというルールで定義されることが望ましいです。最初の単語のみ小文字で初めて、その後は大文字にする形式になります。
また、「_(アンダーバー)」を使うことは推奨されていません。特に、変数名の最初に「_」を使うことは、次回説明しますがクラス内でのプライベート(クラス外からは不可視)変数として特別な意味になるからです。
オブジェクトインスタンスの作成
オブジェクト型のインスタンスを作成する際には、dartは他の言語と同じようにnew演算子を使うことで可能です。ただし、dartの場合、このnewを省略することができます。そのため、リスト11のように記述している内容は同じ意味になります。
var app = new MyApp(); var app = MyApp();
特に、現在ではnewは省略されて記述されるケースが多くなっています。
