Dart-変数の宣言部分を読み解く

Dartで変数の宣言部分についてしらべてみた。
final, const, var, dynamic, 型あたりの話。
Flutter-finalとconstと被っている部分もあるかもしれない。

A tour of the Dart language
A tour of all the major Dart language features.
Dart language specification
The formal specification for the Dart language.

上のページを参照している。

  • 2023/05/14
    Dart 3の仕様に合わせて修正。
    Dart 2.12以降の仕様はDart 3のを見てくれ見たいな感じだったのか。

宣言部分構文

Dartの仕様書を見ると以下の様な定義になっている。

  • Dart 3
    <finalConstVarOrType>
    ::= late? final <type>?
    | const <type>?
    | late? <varOrType>
    <varOrType>::= var
    | <type>
  • Dart 2.10
    <finalConstVarOrType>
    ::= final <type>?

    | const <type>?
    | <varOrType>
    <varOrType>::= var
    | <type>

書き方のバリエーションとしては以下の様な感じになる。

final
final 型
late final
late final 型
const
const 型
var

late var
late 型

  • 2023/05/14 追記
    lateが構文定義の中に入っていた。

final

変数への代入は1度だけ。

仕様上は「初期化時にオブジェクトと変数へのバインドが固定化される」となっている。

const

定数を表し、コンパイル時に定数化されたオブジェクトという位置づけになる。
同一の定数は同一のオブジェクトを利用しているため、一致判断を行うと同一と判断される。

変数はfinalでもあるため、変数へのオブジェクトの再代入はできない。

var

finalやconstではなく、また型推論を使った変数名を宣言するための予約語。

構文のところで「<varOrType>」として宣言された変数名は、finalと異なり、オブジェクトの再代入が可能なものとして位置づけられるため、型宣言がないfinalに対応した宣言方法なのかもしれない。

late

変数に関して仕様書の中にこれといった明示的な書き方はなかった。
constやlateの変数呼び出し時にメソッドのコンパイルエラーが出る場合があるというところ位。

そうでないところには、以下のような記述がある。

  • 宣言後に初期化される 、null 非許容変数の宣言。
  • 変数の初期化を遅らせることができる。

ちなみに「late final」「late var」で宣言された変数はこの段階で代入文がないので、dynamic型になるようだ。

型について

型を指定した場合

<type>として明示した場合、その型を使うことになる。
dynamic型については後述するとして、Objectなどの型を指定することで、静的解析で型で宣言されたアクセス可能メンバーのチェックがなされる。

Object a = “hoge”; と宣言された場合、a.length というStringのプロパティを利用するような実装を行うと、静的解析でエラーとなる。

型推論

<type>として明示的に型を指定しない場合は、型を推論して割り当てられることになる。

決定するための元ネタは、getter側の型を利用する形になるらしい。

var a = “hoge”; と型推論が使われるような宣言がされた場合、aはStringとして認識されるのでa.lengthという実装は可能になる。

dynamic型

<type>にdynamicとして型指定可能なものになるのだけど、この型はObjectと似て、他のクラスのスーパークラス的な扱いのものになる。

Objectとの差は、静的解析時にメンバーアクセスのチェックをしないようになっていること。
(仕様上は「書かれているものは持っていると仮定する」という感じになっている)

dynamic a = “hoge”; と宣言された場合、a.lengthという実装は可能。
この場合、aがStringとして認識されているわけではなく、lengthと書かれた部分をエラーにしないとしているだけ。
dynamic a = 1;と宣言しても、a.lengthは実装可能。

dynamic宣言されている変数が使われる際にメンバーアクセスの可否判断がされ、もし使えないメンバーアクセスがあった場合には例外が出る。

上の様な理由のため、dynamicの利用か所としては「意図的に静的チェックを無効にしたい場合に使用する」ことになり、想定しているのはジェネリック内ということらしい。
ただしその場合でも、実際の使用前にはキャストしてから使ってほしいということらしい。

コメント

タイトルとURLをコピーしました