はじめに
Flutterを網羅的に学習するにあたってRoadmapを使って学習を進めることにしました
この記事では、Flutter初学者やこれからFlutterを学習し始める方に向けて、Flutterロードマップの初期段階であるDart Basics(ダート基礎)についてまとめています。
RoadmapはFlutterだけでなく、他の言語やスキルのロードマップも提供されており、何から学習して良いか分からないと悩んでいる方にとって有用なサイトになっています。
ぜひRoadmapを利用して学習してみてください。
Roadmapとは
簡潔に言えば、Roadmap.shは学習者にとってのガイドブックであり、学習の方向性を提供する学習ロードマップサイトです。
初心者から上級者まで、ステップバイステップでスキルを習得するための情報が提供されています。
学習の進め方が分かりやすく示されているだけでなく、個々の項目に参考資料やリソースへのリンクも提供されているので、学習者は目標を設定し、自分自身のペースで学習を進めることができます。
Dart Basics(ダート基礎)
FlutterロードマップDart Basics(ダート基礎)では以下の6つのサイトが紹介されています。
今回は以下のサイトを利用していませんが、興味のある方はぜひお読みください。
- Dart Overview: https://dart.dev/overview
- What is Dart Programming?: https://www.javatpoint.com/flutter-dart-programming
- Dart Tutorial https://www.geeksforgeeks.org/dart-tutorial/
- About Dart https://flutterbyexample.com/lesson/about-dart
- What is Dart? https://www.youtube.com/watch?v=sOSd6G1qXoY
- Dart in 100 Seconds https://www.youtube.com/watch?v=NrO0CJCbYLA
1. Dartについて
DartはGoogleが開発したオブジェクト指向1のプログラミング言語です。
主にモバイル、Web、デスクトップ、サーバーアプリケーションの開発に使用されます。
JavaとJavaScriptから多くの特徴を受け継いだ静的型付き2のオブジェクト指向言語ですので、JavaやJavaScriptを以前触ったことがある方は、馴染みやすい言語になっていると思います。
静的型付け <=> 動的型付け3
また、DartではJavaScriptモジュール4を入れることで、ブラウザでのDOM操作5など、JavaScriptが担っていたフロントエンドのプログラミングできるようになります。
2. Dartの基礎文法
Dartの基本的な記述法について解説していきます。
Dartでは1つのステートメントごとに、必ず末尾にセミコロン(;
)を付与する必要があります。
セミコロンをつけ忘れると、コンパイルエラーが発生するので、注意してください。
/// エラー
void main() {
var hoge = 'hoge' // セミコロン(;)が付けられていない
print(hoge);
}
/// 実行される
void main() {
var hoge = 'hoge';
print(hoge);
}
Dartでコメントをするには上記のように、スラッシュ (/
) を2つ重ねます。
スラッシュを2つ重ねた箇所以降はDartコンパイラによってコメントとして認識され、プログラムでの処理対象になりません。
複数行のコメントをするには、スラッシュの次にアスタリクス(*
)を配置します。
(*
)がコメントの開始を表します。 コメントの終わりを示すには(*
)の次にスラッシュを配置します。
/*
* hoge
* fuga
* foo
* /
また、コメントしたい部分を選択して「command + スラッシュ(/
)」をすることで、選択した部分をコメントアウトすることもできます。
1. 変数
Dartではvar
を変数名の前に配置して、その次にスペースを空けて変数名を記述することで、変数を定義することができます。
// ① 初期値なし
var hoge;
// ② 変数の宣言時に初期値を代入することも可能です。
var str = 'Fuga';
変数に初期値を定義しなかった場合(上記①など)、デフォルト値はすべてnull
になります。
上記コードをprint文で書くと以下のような結果になります。
// ① 初期値なし
print(hoge); // null
// ② 変数の宣言時に初期値を代入することも可能です。
print(str); // Fuga
1. 型推論
Dartは静的型付き言語なので、var
を使用して変数の宣言と代入を同時に行ったときに、型推論が実行され、自動的に変数の型が決定されます。
var str = 'Fuga';
// is => 指定された型を持っている場合は trueを返します。
print(str is String); // true
変数str
の初期値はString型(文字列)が与えられているので、型推論によりString型になります。
var
を使用せずに、変数の型を指定することも可能です。その場合、指定したい型を変数名の前に置き、スペースを空けて変数名を記述します。
String str = 'Hoge'; // String型
int hoge = 1; // int型
2. 再代入
一度代入した変数に対して、別の値を入れ直すことが可能です。これを再代入と言います。
// int型の変数hogeに対して再代入をしています。
int hoge = 1;
hoge = 2;
hoge = 3;
異なる型の値を代入しようとするとエラーが発生します。
String str = 'Hoge';
str = 2; // String型のstrにint型を代入しようとしているので、エラーが発生する
3. 複数の変数
varに続いてコンマ(,
)で複数記述することで、変数を一度に宣言することができます。
var foo, hoge, fuga;
int foo = 1,
hoge = 2,
fuga = 3;
2. 定数
定数とは値の変更に制限が加えられている変数のことです。
Dartには2つの定数のタイプがあります。
const
はコンパイル時に値が代入され、それ以降変更できないのに対して
final
はプログラムを実行して値が代入されたあと変更できません。
つまり、const
の方がfinal
より制限力が強いということなのです。
1. final
finalを付けて宣言された変数は定数として扱われ、後で別の値を代入することができません。
final int hoge = 1;
hoge = 2 // エラーが発生する
// 型推論を使用した宣言
final hoge = "foo";
print(hoge is String); // true
2. const
constを使用して宣言された変数はコンパイル時に値が代入され、プログラムの実行時に定数として扱われます。
演算子を使って値の中身を計算する必要がある定数を宣言するときなどに使用します。
const double arclength = 2 * 3.14 * 4;
const hoge = 'hoge' + 'fuga' + 'foo';
両者の違いに対してもっと詳しく知りたい方はこちらをご覧ください。
3. 型
Dartは静的型付き言語ですので、使用できる型の特性を理解することが重要です。
1. Int型
整数値を取ることができます。変数の初期値などにint型を指定する場合は、以下の整数リテラル6を使用すると便利です。
- 整数リテラル
// 10進数表記
int a = 1;
int b = 2;
int c = 3;
2. Double型
浮動小数点数を取ることができます。整数部分を最初に表記して、ドット(.
)で区切ることで小数部分を表記します。
- 浮動小数点リテラル
const double pi = 3.141519;
double y = 1.1;
final z = 2.5424;
int、doubleはnumのサブクラスです。
3. String型
文字列を取ることができます。DartではUTF-167の文字コードを使用します。シングルクオート('
)もしくはダブルクオート("
)を使用して文字列リテラルを使用します。
String str1 = "ダブルクオート";
String str2 = 'シングルクオート';
複数行の文字列リテラルはクオートを3つ重ねることで使用できます。
var str1 = '''
複数行の文字列リテラル
複数行の文字列リテラル
複数行の文字列リテラル
''';
var str2 = """
複数行の文字列リテラル
複数行の文字列リテラル
複数行の文字列リテラル
複数行の文字列リテラル
""";
4. Bool型
プログラムで真(True)または偽(False)の2つの値を表現するための型です。
bool型は条件判断や制御フローの判定など、プログラムでさまざまな状況を判断するのに利用されます。真偽の結果によってプログラムの動作を変えることができ、非常に重要なデータ型です。
var hoge = 2;
if (hoge == 1) {
// falseと評価され、実行されない
}
5. List型
リストは複数のオブジェクトを扱うためのコレクション8の型です。
const list = const [1, 2, 3, 4, 5, 6] ;
List<String> list = ['Hoge', 'Fuga', 'Foo']; //型指定する場合
リストの個別の値を取得するにはインデックスナンバーを指定します。
List<int> list = [1, 2, 3];
list[1]; // 2
リストの任意の値に対して再代入を実行することも可能です。
List<String> list = ['Hoge', 'Fuga', 'Foo'];
list[1] = 'one'; // [Hoge, one, Foo]
1. リストの基本メソッド
リストを操作するにあたって基本的なメソッドがいくつか存在します。
- リストに新しい値を追加
List<int> nums = [1, 2, 3];
nums.add(10); // [1, 2, 3, 10]
- 指定した要素に挿入
List<String> strings = ['one', 'two', 'three', 'four'];
strings.insert(3, 'insert'); // ['one', 'two', 'three', 'insert', 'four']
- 指定した要素を削除
List<String> strings = ['one', 'two', 'three', 'four'];
strings.removeAt(3); // ['one', 'two', 'three']
- 指定した値がリストの要素として格納されている場合にそのインデックスナンバーを返す
List<String> strs = ['Hoge', 'Fuga', 'Foo'];
strs.indexOf('Fuga'); // 1
-
要素を比較して昇順に並べる
関数内にあるa
とb
は前後する要素の値です。以下の場合だと最初にa
に1がb
に9が入ります。差が負の場合は、1つ目の要素を2つ目の要素より小さいと判断され、その順序は保持されます。差が0または正の場合は、2つ目の要素が1つ目の要素より小さいと判断され、入れ替えられます。例えば、次のa
に9がb
に4になったときは、9と4が入れ替わります。
List<int> nums = [1, 9, 4, 8, 9, 2, 1, 5, 8, 7];
nums.sort(a, b) => a - b); // [1, 1, 2, 4, 5, 7, 8, 8, 9, 9]
- リストの要素をランダムに変更する
List<int> nums = [1, 9, 4, 8, 9, 2, 1, 5, 8, 7];
nums.shuffle(); // [8, 9, 2, 5, 9, 1, 8, 4, 7, 1]
- リストの各要素を取り出して、取り出した要素を使った任意の処理
int count = 0;
List<int> list = [1, 9, 4, 8, 9, 2, 1, 5, 8, 7];
list.forEach((num) => count += num);
print(count); // 54
-
リストの各要素に任意の処理
forEach
はリストの要素に直接処理を行うのに対して、map
はリストの要素を変換して新しいリストを作成します。
List<int> nums = [1, 2, 3, 4, 5, 6, 7];
nums.map((num) => num * 2); [2, 4, 6, 8, 10, 12, 14]
-
リストの各要素を取り出して、bool値を返す
全ての要素がtrueを返した際はtrue
に1つでもfalseが帰ってきた場合はfalse
を返します。
List<int> nums = [1, 2, 3, 4, 5, 6, 7];
nums.every((num) => num % 2 == 0); // false
List<int> nums = [2, 4, 6, 8, 10];
nums.every((num) => num % 2 == 0); // true
- リストの要素を集計する関数を定義する
List<int> nums = [1, 2, 3, 4, 5, 6, 7];
nums.reduce((a, b) => a + b); // 28
6. Map型
複数の値をキーと関連付けて呼び出すための型です。ハッシュマップ、ハッシュテープと呼ばれるデータ構造に対応します。
全てのキーはユニークである必要があるため、重複は許されません。
コンマ(,
)でペアの集合を区切り、コロン(:
)でキーとキーに対応する値を決定します。
// Map<String, String>
var languages = {
'Python': 'Guido van Rossum',
'Ruby': 'Matumoto Yukihiro',
'PHP' : 'Rasmus Lerdorf'
};
// Map<int, String>
var preciousMetals = {
79: 'gold',
47: 'silver',
78: 'platinum'
};
// キーと値の型を指定して宣言する方法 <- Mapの次に<>で最初にキーの型を、次に値の方を指定する
Map<String, String> map = {
'hoge': 'hoge',
'fuga': 'fuga'
};
-
マップに新しい値を追加する
マップに対して、新しいキーを指定して、その値を代入することで、マップに新しい値を追加することができる。
languages['Perl'] = 'Larry Wall';
- マップに格納された値を取り出す
languages['Ruby'] // 'Matumoto Yukihiro'
- マップの値を固定する
// constを指定することで、変更を防ぐことができる
final preciousMetals = const {
79: 'gold',
47: 'silver',
78: 'platinum'
};
1. マップの基本メソッド
- キーを指定して、値と共に削除する
var languages = {
'Python': 'Guido van Rossum',
'Ruby': 'Matumoto Yukihiro',
'PHP' : 'Rasmus Lerdorf'
};
languages.remove('PHP'); // {Python: GuidovanRossum, Ruby: MatsumotoYukihiro}
- 別のマップを結合する
// 2つのマップの型は一致している必要があります
var languages = {
'Python': 'Guido van Rossum',
'Ruby': 'Matumoto Yukihiro',
'PHP' : 'Rasmus Lerdorf'
};
var languages2 = {
'Perl': 'Larry Wall',
'C++': 'Bjarne Stroustrap'
};
languages.addAll(languages2); // {Python: GuidovanRossum, Ruby: MatsumotoYukihiro, PHP: RasmusLerdorf, Perl: LarryWall, C++: BjarneStroustrap}
- マップの各要素(キーと値)を順番に取り出して処理を行う
var languages = {
'Python': "Guido van Rossum",
'Ruby': "Matumoto Yukihiro",
'PHP' : "Rasmus Lerdorf"
};
String str = "";
languages.forEach((key, value) => str += "<td>" + key + "</td><td>" + value + "</td>");
print(str); //<td>Python</td><td>Guido van Rossum</td><td>Ruby</td><td>Matumoto Yukihiro</td><td>PHP</td><td>Rasmus Lerdorf</td>
- 指定したキーが含まれているかの判定
var languages = {
'Python': "Guido van Rossum",
'Ruby': "Matumoto Yukihiro",
'PHP' : "Rasmus Lerdorf"
};
languages.containsKey('Ruby'); // true
languages.containsKey('Go'); // false
Enum型
Enum型は定数の宣言やプログラムの設定などで使用する型です。
宣言にはenumを変数名の前に宣言する必要があります。
enum Color {red, green, blue}
各要素は、互いに識別することができ、インデックスが割り振られています。
Enumの値は別の変数に代入することが可能です。
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red');
break;
case Color.green:
print('Green');
break;
default:
print(aColor);
}
3. 関数
1. 関数の宣言
関数を宣言するには最初に戻り値の型を指定します。次に関数名を指定して、()
で仮引数をコンマ区切りで与えます。もし引数を取らない場合は、ここは空にします。
関数の処理の中身はブロック{}
で与え、戻り値はreturnで指定します。
return
を呼び出した後は関数の処理は中断され、それ以降の処理は行われません。
int someFunc(int a) {
return a * 2;
}
int someFunc2(int a, int b) {
return a + b;
}
// 戻り値を返さない場合、戻り値の型をvoidを指定する
void someFunc3() {
print("foo");
}
// 関数の処理が1行で済む場合のみ、アロー関数を使用できる
// アロー関数はブロック({})の代わりにアロー(=>)を使用してこの右側に戻り値を与える
bool isHoge(String str) => str == "hoge";
2. 関数のパラメータ
1. 名前付き引数
関数の宣言の際に{}
で仮引数を囲んで宣言すると、関数を呼び出す際に:
を指定して仮引数と関数呼び出すことができるようになります。名前付き引数を使用することで、引数の指定誤りを防ぐことができます。
int someFunc4({int one, int two, int three}) {
return a + b + c;
}
someFunc3(1, 2, 3); // エラー
someFunc3(a: 1, b: 2, c: 3); // 6
2. オプション引数
引数を[]
で囲むことでオプション引数を指定することができるようになります。
オプション引数は引数が与えられないときも関数は正常に実行され、値はnull
となります。
String func(String a, String b, [String c]) {
var result = a + b;
if (c != null) {
result += c;
}
return result;
}
func("hello", " "); // "hello "
func("hello", " ", "world"); // "hello world"
3. 引数のデフォルト値
引数の右側に=
を指定して、引数のデフォルト値を指定することができます。
デフォルト値を設定することができるのは、名前付き引数({})のみです。
仮引数に該当する引数が関数呼び出し時に与えられなかった場合は、デフォルト値が代わりに使用されます。
int someFunc(int a, {int b = 2}) {
return a + b;
}
void main() {
someFunc(1); // 3
someFunc(1, b: 4); // 5
}
4. main関数
main関数はアプリケーションを実行した際に最初に実行される特別な関数です。
戻り値はvoidで、引数は空もしくはコマンドラインの入力値を取るListです。
// test.dart
void main(List<String> args) {
print(args); // [hoge, fuga]
print(args.length); // 2
args.forEach((argv) {
print(argv); // hoge // fuga
});
}
dart test.dart hoge fuga
3. 無名関数(ラムダ関数、クロージャ)
特定のメソッドの実行結果をコールバック9形式で受ける時に使用されます。
var upper = (str) => print(str.toUpperCase());
var list = ['hoge', 'foo', 'fuga'];
list.forEach(upper); // 'HOGE' 'FOO' 'FUGA'
4. ブロック
Dartはブロックで変数のスコープが分離されるので、名前空間10を使用した名前の管理が簡単になります。
{
var a = 1;
{
var a = 2;
print(a); // 2
}
print(a); // 1
{
print(a); // 1
var a = 3;
print(a); // 3
}
print(a); // 1
{
print(a); // 1
}
print(a); // 1
{
print(a); // 1
var a = 4;
print(a); // 4
}
}
5. クロージャ
クロージャは構文上のスコープ内の変数にアクセスすることができる関数であり、オリジナルのスコープから外れていても使用することができます。
Function curriedFunc(num x) {
return (num y) => x + y;
}
void main() {
var hoge = curriedFunc(3);
var fuga = curriedFunc(5);
hoge(4); // 7
fuga(6); // 11
curriedFunc(4)(5); // 9
}
4. 演算子
1. 算術演算子
算術演算子は基本的な四則演算を実行するのに使用される演算子です。
var a = 1 + 2; // 3 加法(+)
var b = 2 - 1; // 1 減法(−)
var c = -b ; // -1 符号反転(-expr)
var d = 3 * 4; // 12 乗法(*)
var e = 6 / 2; // 3 除法(/)
var f = 10 ~/ 3; // 3 除法 小数点以下切り捨て(~/)
var h = 10 % 3; // 1 剰余 整数の割り算余り(%)
前置・後置演算子も用意されています。
var a = 3;
++a; // 4
var b = 4;
b++; // 5
var c = 5;
--c; // 4
var d = 6;
d--; // 5
2. 等価・比較演算子
値の等価性や大小の比較を行うための演算子です。
1 == 1; // true 左辺と右辺が等しい(==)
2 == 1; // false
2 != 1; // true 左辺と右辺が等しくない(!=)
2 != 2; // false
3 > 2; // true 左辺が右辺より大きい(>)
2 > 3; // false
3 < 2; // false 右辺が左辺より大きい(<)
2 < 3; // true
2 >= 3; // false 左辺が右辺より大きいか等しい(>=)
3 <= 2; // false 右辺が左辺より大きいか等しい(<=)
3. 型演算子
変数に対してis
を使用することで、その変数の型とその型が一致しているかをbool型で返します。
演算子 | 意味 |
---|---|
as | 型変換を行う (サブタイプの場合) |
is | 型チェック (指定した型と一致するかを検証する) |
is! | 否定型チェック (指定した型と異なっているかを検証する) |
String hoge = "hoge";
if (hoge is String) {
print(hoge); // hogeがString型の場合のみ呼び出される
}
4. 代入演算子
代入や代入と同時に任意の演算を実行することができます。
演算子 | 意味 |
---|---|
= | 代入 |
-= |
var -= var2 は var = var - var2 と同じ |
/= |
var /= var2 は var = var / var2 と同じ |
%= |
var %= var2 は var = var % var2 と同じ |
+= |
var += var2 は var = var + var2 と同じ |
*= |
var *= var2 は var = var * var2 と同じ |
~/= |
var ~/= var2 は var = var ~/ var2 と同じ |
<<= |
var <<= var2 は var = var << var2 と同じ (ビットを右にシフトする操作) |
>>= |
var >>= var2 は var = var >> var2 と同じ (ビットを左にシフトする操作) |
^= |
var ^= var2 は var = var ^ var2 と同じ |
&= |
var &= var2 は var = var & var2 と同じ |
|= |
var &= var2 は var = var | var2 と同じ |
-
左シフト演算子 (<<):ビットを左にシフトします。左にシフトすると、数値は2のべき乗倍されます。例えば、x << y は x を y ビットだけ左にシフトします。
-
右シフト演算子 (>>):ビットを右にシフトします。右にシフトすると、数値は2のべき乗で割られた結果になります。
-
非排他的論理和(^):2つの値の対応するビットが等しい場合に1を返し、異なる場合に0を返すビット単位の論理演算です。XOR(排他的論理和)とは逆の振る舞いをします。
-
論理積(&):2つの論理値(真または偽)を比較する論理演算です。この演算は、両方の論理値が真(true)の場合にのみ真を返し、それ以外の場合は偽(false)を返します。
-
論理和(|):2つの論理値(真または偽)を比較する論理演算です。この演算は、どちらかまたは両方の論理値が真(true)の場合に真を返し、両方の論理値が偽(false)の場合にのみ偽(false)を返します。
5. 論理演算子
複数の等価・比較演算子をつなげて条件分岐の処理を行うときに使用されます。
演算子 | 意味 |
---|---|
!expr | bool型のtrueとfalseを逆転させる |
| | OR |
&& | AND |
6. その他演算子
演算子 | 名前 | 意味 |
---|---|---|
() | 関数の適用 | 関数の呼び出し時に使用する |
[] | リストへのアクセス | リストの特定のインデックスに該当する要素を呼び出す |
. | メンバへのアクセス | オブジェクトのプロパティにアクセスする時に使用する |
?. | 条件付きメンバへのアクセス | プロパティがnullを取る場合に安全にアクセスする ために使用する |
7. 三項演算子
?
の直前にbool型の戻り値を返す関数や演算を行い、true
が返ってきた場合には、最初の要素が、false
が返ってきた場合には次の要素が返ります。
// 三項演算子を使用することで条件分岐が簡潔になります
var x == 3;
x % 3 == 0 ? 'hoge' : 'fuga';
5. 構文
1. if -else構文
条件分岐を行うために使用します。ifに続く()
の中でbool型の戻り値を与える評価式を記述することで条件分岐を実行する。
if (isHoge()) {
print('Hoge');
}
ifの後にelse
を記述することで条件が成立しなかった場合の処理を記述することが可能です。
// isHoge()がtrueを返さなかった場合elseの処理が呼ばれる
if (isHoge()) {
print('Hoge');
} else {
print('noHoge');
}
2つ以上の条件を指定する場合はelse if()
を指定することで条件式を複数記述できます。
if (isHoge()) {
print('Hoge');
} else if(isFoo()) {
print('foo');
} else {
print('noHoge');
}
2. forループ構文
for (var i = 0; i < 5; i++) {
print(i);
}
// 結果
// 0
// 1
// 2
// 3
// 4
// 5
// Listをループする場合はfor-in構文を使用する
List<String> list = ['foo', 'fuga', 'hoge'];
for (String i in list) {
print(i);
}
// 結果
// foo
// fuga
// hoge
3. while構文
whileの後に条件式を記述することでループを記述することができます。
while (isFuga()) {
print('fuga');
}
1. break文
whileループの実行途中にbreak
が呼び出されるとループが停止される。
無限ループを任意のタイミングで停止するときに使用されます。
import 'dart:math';
// 0.95以上の数値が出たタイミングで無限ループを停止する
void main() {
var rng = new Random();
while(true) {
var rm = rng.nextDouble();
if(rm >= 0.95) {
break;
}
print(rm);
}
}
2. continue文
whileの中でcontinueが実行されると、それ以降の文が実行されずに次のループに移行します。
import 'dart:math';
// 0.1未満の数値が出た場合にその数値を出力せずに次のループに移行する
void main() {
var rng = new Random();
while(true) {
var rm = rng.nextDouble();
if(rm < 0.1) {
continue;
}
if(rm >= 0.95) {
break;
}
print(rm);
}
}
3. do-while文
do
ブロック内の処理が終わってからwhileの中の処理が実行されます。
import 'dart:math';
void main() {
var rng = new Random();
double rm;
do {
rm = rng.nextDouble();
print(rm);
} while(rm <= 0.95);
}
4. switch文
ある値に対して複数の候補と等しいかどうかを検証するときに使用します。
switchで与えた引数はcaseで指定した値と等しいかどうかを上から順番に行います。等しい場合はcaseで指定されたブロックの中身の演算が実行されます。
もし、caseで指定されたどの値とも等しくない場合は、defaultの中身が実行されます。
// case内でbreakが指定されていないと処理が最後まで行われるので、余分な処理を省くためにbreakの記述は必要です。
switch (language) {
case 'PHP':
print('PHP');
break;
case 'Python':
print('Python');
break;
case 'Ruby';
print('Ruby');
break;
default;
print('unknown');
}
5. assert文
コードのテストに便利なassert文です。assertで指定した演算結果としてfalseが返されると警告文が出力されます。
assert(x == 2);
リリースモード
で実行する時にはassertは無視されるため、円滑なテストが可能になります。
リリースモード:プログラムの実行を継続できないエラーが発生しない限り、なるべくエラーを無視してそのまま実行を続けようとします。また、できるだけ速く実行するために、型のチェックなども行われません。
デバッグモード:バグの原因と考えられる問題をなるべく早く検出するため、静的な型のチェックだけでなく、動的な方のチェックやassertによるチェックも有効になります。
https://hiyoko-programming.com/1590/
開発時はデバッグモードを、リリース時はリリースモードを使用します。
6. try-catch-finally文
例外(Exception)時の処理を書いておかないと、例外が発生した場合にコードが異常終了する恐れがあります。安全なプログラムを記述するには例外を捕捉することが重要です。
1. 例外を発生させる
例外を発生させるにはthrow
という演算子を指定します。
throw 'Hoge'
new FormatException('Excepted at least 1 section');
2. try-catch
try
のスコープ内で発生した例外を捕捉してcatch
のスコープ内で適切な処理を行うことができます。
// tryで例外が発生した場合は、tryのスコープ内でそれ以降処理は行われません
// 例外のタイプ別に分けるにはonの後に例外の型を指定します。全ての例外を捉えるにはExceptionを指定します。
try {
someFunc1();
} on OutOfMemoryException {
someFunc2();
} on Exception catch (e) {
print(e);
} catch (e) {
print(e);
}
3. スタックトレース
スタックトレース11を見るにはcatch
に2つ目の引数を指定します。
try {
// 処理
} on Exception catch (e) {
print(e);
} catch (e, s) {
print(e);
print(s);
}
4. finally
例外発生の有無に関わらず必ず実行する処理を記述したい場合はfinally
のスコープ内に処理を記述します。
try {
// 処理
} catch (e) {
print(e);
} finally {
// 例外発生の有無に関わらず実行される
}
6. クラス
クラスからオブジェクトを生成するにはnew
を使用してコンストラクタを呼び出します。
var v1 = new Vehicle(120);
オブジェクトは関数やメンバを保有しています。メソッドを呼び出すときは、オブジェクトからそれを呼び出します。メソッドはオブジェクトの関数とデータを使用することが可能です。
.
を使用することでオブジェクトの変数やメソッドにアクセスすることができます。
また、?.
を代わりに使用することでnull
である可能性のあるプロパティにアクセスするときに例外は発生するのを防ぐことができます。
var v1 = new Vehicle(120, 1.2);
v1.weigth = 150
1. プロパティ
1. static変数
変数の前にstatic
を指定することで全てのクラスのインスタンスで共有される変数を宣言することができるようになります。
class Car {
static const String brandName = "Toyota";
// ...
}
var car1 = new Car(150, 1.2);
var car2 = new Car(180, 1.4);
print(car1.brandName); // Toyota
print(car2.brandName); // Toyota
2. コンストラクタ
クラスと同じ名前のメソッドを宣言することでコンストラクタ12を宣言することができるようになります。
コンストラクタはクラスのインスタンスの初期値をリセットするために使用されます。
class Vehicle {
num weight, height;
Vehicle(num weight, num height) {
this.weight = weight;
this.height = heigth;
}
}
// コンストラクタはインスタンスを確保して変数を宣言する時に呼び出されます。
var car1 = new Car(150, 1.2);
print(car1.weight); // 150
print(car1.heigth); // 1.2
1. コンストラクタの継承
サブクラスはスーパクラスのコンストラクタを呼び出すことはありません。サブクラスで再び新しく宣言し直す必要があります。
3. メソッド
メソッドはクラスのメンバである関数です。
class Car extends Vehicle {
Car(num weight, num height): super(weight, height);
void beep() {
print("beep");
}
}
var car1 = new Car(150, 1.2);
car1.beep(); // beep
1. staticメソッド
static
が付与されたメソッドは、インスタンスに対しての直接操作を行うことができません。
代わりにインスタンス化せずに呼び出せるメソッドとして引数をとって演算を行うことが可能です。
class someClass {
static void someStaticMethod() {
// 処理
}
}
someClass.someStaticMethod(); // インスタンス化をせずに呼び出せる
2. カスケード表記
同じインスタンスに対して複数のメソッドを続けて適用したり、特定のプロパティへの代入を繰り返すなど、複数の操作を行う際に使用します。
カスケード表記は、メソッド呼び出しを行う場所で、本来インスタンスが現れるところに、.
を配置することで利用できます。 つまりカスケード表記は.
を2つ連続で重ねる形になります。
// カスケード表記なし
request.response.headers.contentType = new ContentType("text", "plain", charset: "utf-8");
request.response.write("Hello, world");
request.response.close();
// カスケード表記あり
request.response
..headers.contentType = new ContentType("text", "plain", charset: "utf-8")
..write("Hello, world")
..close();
4. クラスの継承
extends
を使用することでクラスを継承してサブクラスを宣言することができます。
継承元のクラス(スーパークラス)のコンストラクタを呼び出すにはsuper
を使用します。
class Vehicle {
num weight, height;
Vehicle(num weight, num height) {
this.weight = weight;
this.height = height;
}
}
class Car extends Vehicle {
Car(num weight, num height): super(weight, height);
void beep() {
print("beep");
}
}
1. メソッドのオーバーライド
サブクラスからスーパークラスのメソッドを上書き(オーバーライド)して新しくメソッドを定義し直すことが可能です。
メソッドのオーバーライドを行っていることを示すためにメソッドの前に@override
を追記します。
class Ambulance extends Car {
@override
void beep() {
print("whoop");
}
}
2. noSuchMethod()
存在しないメソッドを呼び出し場合に呼び出されるnoSuchMethod()
をオーバーライドすることが可能です。
class A {
@override
void noSuchMethod(Invocation invocation) {
// エラー処理など
}
}
5. ジェネリクス
ジェネリクスは総称型とも呼ばれます。
静的型付き言語で、Listなどコンテナ型のオブジェクトに対してメソッドを定義する際に役に立つ機能です。
bool isAllItemHoge(List<String> hoge) {
// 処理
}
bool isAllItemHoge(List<num> hoge) {
// 処理
}
// ジェネリクスを使用することでListの要素の型ごとに関数を実装する必要がなくなります
bool isAllItemHoge(List<T> hoge) {
// 処理
}
参考資料
告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。
みなさまからのご応募をお待ちしております。
-
オブジェクト指向言語
「ある役割を持ったモノ」ごとにクラスを分割し、モノとモノとの関係性を定義していくことでシステムを作り上げようとするシステム構成の考え方のこと。
簡潔に言うと「モノ(どんな奴でどう動く)」に注目した考え方のことです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
静的型チェック
コードの実行前に変数や式の型を検査する仕組みです。
コンパイラや開発環境がコードを解析し、変数や関数の型情報をチェックします。その結果、変数が予期しない型で使用されている場合や、型に関連するエラーや警告が見つかった場合に、開発者に通知されます。
型は必須ですが、型推論のため、型アノテーションはオプションです。 ↩ -
動的型チェック
コードが実行される際に変数や式の型を検査する仕組みです。
コンパイル時ではなく、実行時に型情報を検査します。変数や式が使用されるたびに、その時点での型情報を確認し、型に関連するエラーや警告を検出します。 ↩ -
モジュール
プログラムにおいて特定の機能を持ったひとまとまりの構成要素です。
簡潔に言うと、単独でも機能としては成立するけど、普通は他のものと組み合わせて使うような部品のこと
こちらにわかりやすい記事があったので、是非読んでみていください。 ↩ -
DOM(Document Object Model)操作
JavaScriptを使用してWebページの要素や構造を変更するための技術です。
Webページは、HTMLで作成されます。DOMを用いることで、HTMLの各要素にアクセスするためのメソッドやプロパティを使用できます。例えば、ユーザーの操作に応じてページの内容や見た目を変更することができます。 ↩ -
整数リテラル
ソースコードの中に直接べた書きした整数のことです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
UTF-16
文字コード(文字に割り当てられた数字)の用語のひとつです。もう少し噛み砕いていうと『文字に割り当てた番号』と『実際にコンピュータさんが扱う数字』の対応表のことです。
こちらにわかりやすい記事があったので、是非読んでみていください。 ↩ -
コレクション
データやオブジェクトなどをまとめて格納するためのデータ構造やクラスなどの総称のことです。 ↩ -
コールバック
あるイベントが発生した時に関数の引数として呼び出される関数のことです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
名前空間
各要素に一意の異なる名前をつけなければ識別できない範囲のことです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
スタックトレース
実行中のコンピュータプログラムにエラーが発生した際に、直前に実行していた関数やメソッドなどの履歴を表示することです。
こちらにわかりやすい記事があったので、是非読んでみてください。 ↩ -
コンストラクタ
インスタンスを作成したタイミングで実行されるメソッドのことです。
(クラスをnewしたタイミングで実行される関数)
最初にやっておかなければならない処理、例えばメンバ変数の初期化処理などによく活用されます。
ただし、コンストラクタには戻り値が返せないという制限もあります。 ↩