Pythonしか知らない人向けのDart文法

# はじめに

Pythonが初めてのプログラミング言語だった方向けにDartの文法についてまとめました．Pythonと違うところにだけ注目してまとめました．

flutter公式サンプルのカウンターアプリのコードが理解できるレベルを目標にしています．

間違い等ありましたら，遠慮なくコメントください！

**以降の説明ではシンプルに書くために、[`main`関数](#main関数)は省いてあります。**実際に動かすときには`main`関数の中に記述する必要があります。また，型注釈があってもなくてもいいときは，[型注釈](#型注釈)をつける文法のみを紹介します．

# `main`関数
プログラムの中に`main`という名前の関数を1つ絶対に定義しなければならない。`main`関数が一番最初に呼び出されてプログラムがスタートする．

# 型注釈
基本的に型注釈が必要．型注釈というのは**変数や関数の戻り値の型をコード中に明記する**こと．動的型付けのPythonと違って，Dartは型注釈が必要な静的型付けである．一応動的型付けもサポートはされているが，静的型付けに従うのが吉．メリットは色々あるが一番しっくり来るのは，関数の中身のコードを読まなくても関数名と型注釈を確認するだけで，その関数がどの型に対してどんな変換を行なってどの型を返すのかという情報がひと目でわかるから．

**型注釈は関数や変数の定義時に，関数名や変数名の前に書く．**変数や関数の定義の仕方については後ほど説明するので，ここでは型注釈は定義時に名前の前に記述するということだけ把握しておいてください．

```dart
int variable;
int function(int variable0, int variable1){}
```


# 基本的なルール

行の末尾にセミコロンを書く必要がある。

```dart
print("hoge");
```
インデントではなく、`{}`でまとまりを表す。中括弧のあとにセミコロンはいらない。

```dart
hoge(){
  print("hoge");
}
```

# 型注釈


# コメント

```dart
// coment

/*
hoge
hoge
hoge
*/

///document
///document
```

# 変数

定義と代入は別の作業であり、代入をする前に`var`を使って変数を定義する必要がある。

```dart
var hoge; 
```




定義と代入を一行で書くこともできる。

```dart
var hoge = 0;
```


`var`の代わりに、型を指定して定義することもできる。この場合はその変数にはその型のオブジェクトした代入できないようになる。

```dart
int hoge;
```

先頭にアンダースコアを一つつけるとprivate扱いになり、クラスの外からアクセスすることができなくなる。

```dart
int _hoge = 2; 
```

# 定数

`const`や`final`を使うことで定数を定義できる。使い分けについて現在咀嚼中
参考になりそうなリンクだけ貼っておきます。
https://qiita.com/uehaj/items/7c07f019e05a743d1022#final%E6%8C%87%E5%AE%9A
https://stackoverflow.com/questions/50431055/what-is-the-difference-between-the-const-and-final-keywords-in-dart


そもそも定義時に使用するものなので、`var`をつけなくてもOK。

```dart
final hoge;
```


もちろん型を指定することもできる。

```dart
const int hoge =0;
```



# 文字列への変数の埋め込み

ドルマーク`$`の後に変数名を書くことで変数を文字列中に埋め込める。String型以外の場合には、自動的にString型に変換される。

```dart
var hoge = 0;
print("hoge refers $hoge");
```

純粋な変数ではないもの(フィールドとか)を埋め込みたいときは中括弧でくくる。

```dart
print("1 + 1 = ${1 + 1}");
```



# 型変換
int型からString型に変換するときは以下のようにする。文字列に埋め込むために変換したい場合は[変数の埋め込み](#文字列への変数の埋め込み)を使う。コンソールに`print`するときなど、String型以外のものを文字列で表したいことは多々あるので、`toString`メソッドは大抵のオブジェクトに定義されている。

```dart
String oneAsString = 1.toString();
```
String型からint型に変換するときは以下のようにする。`toStirng`メソッドと違って`parse`メソッドはint型特有のメソッドである。

```dart
var one = int.parse('1');
```




# 関数

`def`のような、関数の定義の前置きはない。関数名の前に戻り値の型を宣言することができる。戻り値を返さないのは`void`という型になる。

```dart
int hoge(int number){
  return number;
}
```



関数の中のコードが一行しかない場合は、`=>`という矢印のマークを使って見やすいコードが書ける。`=> 式`と`{ return 式; }`は同じ意味。

```dart
void main() => print("hoge");
```

## 名前付き引数

中括弧でくくった引数は、引数名を指定して引数を渡すことができるようになる。名前付き引数はオプション引数の部類に含まれることになるので、省略することもできる。省略した場合`null`が返される。Pythonとは違って、名前付き引数でないと引数名を指定して渡すことはできない。

```dart
int hoge({int number}){
  return number;
}
```


省略させたくないときは、`@required`をつけて強制することもできる。ただし、このアノテーションを使うには`package:meta/meta.dart`をインポートする必要がある。

```dart
int hoge({@required int number}){
  return number;
}
```


引数名を指定して関数を呼び出すときはコロン`:`を使って引数を指定する。

```dart
hoge(name : "Mike");
```



# 演算子

メジャーな演算子のうち、PythonとDartで異なるものだけをまとめた。

| Dart | Python |
| ---- | ------ |
| ~/   | //     |
| ++   | +=1    |
| --   | -=1    |
| &&   | and    |
| &#124;&#124;   | or     |

## `??=`
代入演算子の一つ。nullのときにだけ特定の処理をさせることはよくあるので、便利な演算子が用意されている。この演算子は、左辺ががnullのときだけ代入処理を行う。

```dart

int a;
a ??= 3;
```
aには最終的に３が代入される。

## `??`
上の演算子と似ているが、こちらは値を返す。左側がnullのとき右側を返す。

```dart
int a;
print(a ?? 3)
```

3がコンソールに出力される。

# 制御文

条件は`()`でくくる。

## if

異なるのはこれだけ。

| Dart      | Python |
| --------- | ------ |
| `else if` | `elif` |

## if-elseの代替構文
条件によって返す値を変えたいということはよくある。そんなときのために便利な構文が用意されている。
`bool値　? 式　: 式`という形で使用する。bool値がTureのときコロンの左側の式を返し、Falseのとき右側を返す。なるべく式がシンプルな場合に使うと良いだろう。

```dart
var isPerson = true;
print(isPerson ? "Yes": "No");
```
この場合、Yesと出力される。

## for

条件の部分は`(変数定義と代入; 継続条件; 継続時処理)`というような書き方。

```dart
for (int number = 0; number < 3; number++){
  print(number);
}
```


Pythonのコードと似ている書き方にも対応している。

```dart
var numbers = [0, 1, 2];
for (var number in numbers) {
  print(number); 
}　
```


## switch

あることにはあるが、Pythonでは使わずにやってきたのでとりあえず割愛。

# `import`

Pythonでは、パッケージやモージュールの名前を指定するが、DartではURIを指定する。URIは識別子ではなく文字列なのでシングルクォーテーションやダブルクォーテーションでくくる。ちなみにURIというのはURLの進化形で、「URLで使われるhttpとかhttpsとかのスキーム以外も利用して、万物にURLみたいな名前を付けよう！」的な考えをもとに作られた表記方法。URIの構成は`スキーム:パス`となっている。[^1]パッケージを利用するときのスキームは`package`、Dartの組み込みライブラリを利用するときは`dart`。

単に別ファイルのdartファイルを読み込みたい場合は絶対パスか相対パスを入力する。



# アノテーション

`@`で始まる文はアノテーションと呼ばれ、メソッドなどに特定の性質を割り当てたりするのに利用される。Pythonでいうデコレータ的なもの。

# クラス

## クラス変数とインスタンス変数

クラス変数とインスタンス変数の違いは、`static`をつけて修飾するかしないかということ。修飾した場合、クラス変数として扱われ、クラスに共通な変数として扱うことができる。定義する場所はクラス変数もインスタンス変数もclass直下。

Pythonのクラスについて理解が怪しい場合は[こちらの拙著](https://qiita.com/basashi/items/69fee6df0f23f140e91c#q3-%E3%82%AF%E3%83%A9%E3%82%B9%E5%A4%89%E6%95%B0%E3%81%A8%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E5%A4%89%E6%95%B0%E3%81%AE%E9%81%95%E3%81%84)をどうぞ。

```dart
class JapanesePerson{
  static String nationality = "Japan";　// クラス変数
  int age; // インスタンス変数
  String name;　// インスタンス変数
}
```

## `this`

Pythonのように、インスタンスをselfという引数としてメソッドに与えるという作業は必要ない。Dartではthisはメソッド内で使用する時、自分自身を返す特別な変数である。

```dart
class Person{
  String name;
  void info(){
    print("My name is ${this.name}");
  }
}
```



## コンストラクタ

1. クラスと全く同じ名前

2. 戻り値の型が指定されていない

3. 戻り値がない

のすべてを満たしたメソッドがコンストラクタとして認識される。 

```dart
class Person{
  String name;
  Person(name){
      this.name = name;
  }
}
```



以下コンストラクタのいろんな機能

### Syntactic sugar（便利な構文）

コンストラクタの引数にインスタンス変数を渡すと自動的に代入処理が行われる。上のコードとやってることは全く同じ。

```dart
class Person {
  String name;
  Person(this.name);
}
```

### 名前付きコンストラクタ

DartやPythonではオーバーロード(同じ名前のコンストラクタを定義して、変数の数によって自動的に使い分けてくれる機能)がない。その代替策として、`クラス名.任意名称()`とすることで複数のコンストラクタを作ることができる。インスタンス化するときも、`クラス名.任意名称()`と言うようにして呼び出す。

```dart
class Person{
  String name;
  Person(name){
      this.name = name;
  }
  Person.gest(){
      this.name = "gest";
  }
}
```

### 定数コンストラクター

インスタンスの持つフィールドの値が変化しないオブジェクトをインスタンス化したいときに使いう。すべてのフィールドを定数にして、コンストラクタの先頭に`const`をつける必要がある。

```dart
class Hoge{
  final name;
  const Hoge(this.name); 
}
```

### コンストラクタのリダイレクト

コロンの後に別のコンストラクタを記述することで、別のコンストラクタを呼び出して処理をバトンタッチすることができる。この場合のthisは自分自身、つまりPersonを返しているので、Personコンストラクタに`"gest"`を渡していることになる。

```dart
class Person{
  String name;
  Person(name){
    this.name = name;
  }
  Person.gest(): this("gest");
}
```



## 継承

Pythonでは親となるクラスは`()`に記述するが、Dartでは`extends`のあとに記述する。

```dart
class Person{
  int age;
  String name;
}

class JapanesePerson extends Person{
  static String nationality = "Japan";
}
```

### `super`

`super`は親クラスを返す。superの部分がクラス名に化けると考えてよいので、`super()`とすると親クラスのコンストラクタを呼び出すことになる。

Pythonとの大きな違いは**コンストラクタの中で`super`は使えない**という点。これを回避するためにコンストラクタのリダイレクトを使う。

親クラスのコンストラクタを呼び出すときはこんな感じ。[コンストラクタのリダイレクト](#コンストラクタのリダイレクト)と[Syntactic sugar](#syntactic-sugar便利な構文)を応用している。

```dart
class Person{
    int age;
    String name;
  Person(this.age, this.name);
  info (){
    print("My name is ${this.name}.");
  }
}

class JapanesePerson extends Person{
  static String nationality = "Japan";
  var prefecture;
  JapanesePerson(age, name, this.prefecture): super(age, name);//ココ
}
```



### オーバーライド

アノテーションとして`@override`を上の行につける必要がある。

```dart
@override
info(){
  print("hoge");
}
```



## setter/getter



# `assert()`

簡易的に関数のテストを行うために使う。ただしこの方法ではテストが失敗したときに，実際にはどんな値が返されたのか表示してくれないので実際にデバッグするときに手間がかかる．そのため，基本的にtestパッケージを使うのがおすすめ．assertは使い捨てのコードなど，テストのためのコードをきっちりとかくのが馬鹿らしいときに使う．

```dart

assert(n == 1);
```

# 参考にしたサイト

[Dart documentation | Dart](https://dart.dev/guides)

[DartPad](https://try.dartlang.org/dart)

[初心者のためのDart 2入門](https://www.tuyano.com/index2?id=5650082896543744)

[Dartのコンストラクタについて | Developers.IO](https://dev.classmethod.jp/articles/about_dart_constructors/)



[^1]: パスの部分なんですけど、httpの場合ってパスの先頭が`//`ってなってますよね？これはスキームがhttpの時だけのルールみたいです。