Dartメモ
目次:
関数
Dartは真のオブジェクト指向言語。関数でもオブジェクトであり、Function型を持っている。関数で変数を作ることができて、関数の引数として使うことができる。詳しくは、コーラブルクラスを参照 関数を実装する例:
code:dart
bool isNoble(int atomicNumber) {
}
code:dart
isNoble(atomicNumber) {
}
簡略構文を使うこともできる:
code:dart
bool isNoble(int atomicNumber) => _nobleGasesatomicNumber != null; => expr構文は{ return expr; }の簡略構文。=>記法はアロー構文として呼ばれることがある。
関数は二つの型(requiredとoptional)を持つことができる。requiredは初めにリストされる、optionalはnamedとpotencialを決めることができる。
optionalパラメーター
optionalパラメーターはnamedとpotencialのどちらか一方を指定できる。
namedパラメーター
関数が呼ばれたとき、paramName: valueを使うことでnamedパラメーターを特定できる。例えば:
code:dart
enableFlags(bold: true, hidden: false);
関数を定義するとき、namedパラメーターの{param1, param2, …}を使うこと:
code:dart
void enableFlags({bool bold, bool hidden}) {...}
namedパラメーターはたくさんのoptionalパラメーターで、パラメーターが必須であることを知らせる@requiredを注釈付けることができる。 例えば:
code:dart
const Scrollbar({Key key, @required Widget child})
potentialパラメーター
[]で関数パラメーターの集合を包むことでoptional positionalパラメーターとして印をつける:
code:dart
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
}
optionalパラメーターなしの関数:
code:dart
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
第3引数を入れたもの:
code:dart
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
デフォルトパラメーター値
namedとpotencialパラメーターの両方のデフォルトの値を定義するために使うことができる。もしデフォルト値がない場合、デフォルト値はnull。
namedパラメーターのデフォルト値を設定する例:
code:dart
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold will be true; hidden will be false.
enableFlags(bold: true);
dartではコロンではなくイコールを使ってでの設定が推奨されている。
positionalパラメーターのデフォルト値の例:
code:dart
String say(String from, String msg,
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
デフォルト値にリストもしくはマップを渡すことができる。
listパラメーターのデフォルトリストとgiftsパラメーターのデフォルトマップを特定するdoStuff()の例:
code:dart
void doStuff(
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
main()関数
あらゆるアプリはトップレベルmain()関数をもつ。アプリのエントリーポイントとして提供する。main()関数はvoidを返して、引数のoptionalList<String>をもつ。
webアプリのmain()関数の例:
code:dart
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
引数を取ってくるコマンドラインアプリのmain()関数の例:
code:dart
// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments0) == 1); assert(arguments1 == 'test'); }
ファーストクラスオブジェクトとしての関数
その他の関数にパラメーターとして関数を渡すことができる。
code:dart
void printElement(int element) {
print(element);
}
// Pass printElement as a parameter.
list.forEach(printElement);
変数に配置することができる:
code:dart
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
このコードは無名関数を使っている。
無名関数
main()もしくはprintElement()のように、たいていの関数はnamed。名前のない無名関数を作ることができる。
code:dart
codeBlock;
};
型のないパラメーター、アイテムによって無名関数を定義する例:
code:dart
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
アロー関数で一行でできる:
code:dart
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
レキシカルスコープ
Dartはレキシカルなスコープされた言語。変数のスコープは静的に決められる。
様々なスコープレベルでの変数のネストされた関数の例:
code:dart
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
nestedFunction()はあらゆるレベルから変数を使うことができる。
レキシカルクロージャ
クロージャは、関数がオリジナルスコープの外側で使われるときに、レキシカルスコープでの変数にアクセスした関数オブジェクト。
次の例では、makeAdder()は変数addByをとる。
code:dart
/// Returns a function that adds addBy to the /// function's argument.
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
関数が等しいかテストする
トップレベルの関数、静的メソッド、インスタンスメソッドが等しいかどうかをテストする例:
code:dart
void foo() {} // A top-level function
class A {
static void bar() {} // A static method
void baz() {} // An instance method
}
void main() {
var x;
// Comparing top-level functions.
x = foo;
assert(foo == x);
// Comparing static methods.
x = A.bar;
assert(A.bar == x);
// Comparing instance methods.
var v = A(); // Instance #1 of A var w = A(); // Instance #2 of A var y = w;
x = w.baz;
// These closures refer to the same instance (#2),
// so they're equal.
assert(y.baz == x);
// These closures refer to different instances,
// so they're unequal.
assert(v.baz != w.baz);
}
値を返す
すべての関数は値を返す。もし戻り値が設定されていない場合、return nullになる。
code:dart
foo() {}
assert(foo() == null);
クラス
Dartはクラスとミックスインベース継承のオブジェクト指向言語。あらゆるオブジェクトはクラスのインスタンスで、全てのクラスはオブジェクトから降りる。ミックスインベース継承はあらゆるクラスが明確な一つのスーパークラスを持ち、クラスボディは複数のクラス階層で再利用されるという意味。拡張メソッドはクラスを変更したりサブクラスを作らないでクラスの機能を加える方法。 クラスメンバーを使う
オブジェクトは関数とデータ(メソッドとインスタンス変数など)から構成するメンバーを持つ。メソッドはオブジェクトの関数とデータにアクセスする。
インスタンス変数もしくはメソッドを参照するのにドット(.)を使うこと。
code:dart
var p = Point(2, 2);
// Set the value of the instance variable y.
p.y = 3;
// Get the value of y.
assert(p.y == 3);
// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4, 4));
左端のオペランドがnullであるとき、例外を避けるために.の代わりに?.を使うこと:
code:dart
// If p is non-null, set its y value to 4.
p?.y = 4;
コンストラクターを使う
コンストラクターを使ってオブジェクトを作ることができる。コンストラクターはClassNameとClassName.identifierのどちらかで作ることができる。Point()とPoint.fromJson()コンストラクターを使うPointオブジェクトの例:
code:dart
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
以下のコードは同じ効果を持つが、コンストラクター名の前に任意のnewキーワードを使うこと:
code:dart
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
newキーワードはDart 2では任意。
クラスは定数コンストラクターを提供する。定数コンストラクターを使ってコンパイル時定数を作るために、コンストラクター名の前にconstを付けること: code:datr
var p = const ImmutablePoint(2, 2);
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // They are the same instance!
コンストラクターもしくはリテラルの前のconstを省略でき、定数マップを作る例:
code:dart
// Lots of const keywords here.
const pointAndLine = const {
};
constキーワードの最初の使用以外はすべて省略できる:
code:dart
// Only one const, which establishes the constant context.
const pointAndLine = {
};
もし定数コンストラクターがconstなしで呼び出されたら、非定数オブジェクトを作る:
code:dart
var a = const ImmutablePoint(1, 1); // Creates a constant
var b = ImmutablePoint(1, 1); // Does NOT create a constant
assert(!identical(a, b)); // NOT the same instance!
オブジェクトの型を手に入れる
オブジェクトの型を取得するために、オブジェクトのruntimeTypeプロパティを使うことができ、Typeオブジェクトを返す: code:dart
print('The type of a is ${a.runtimeType}');
インスタンス変数
インスタンス変数の宣言方法:
code:dart
class Point {
num x; // Declare instance variable x, initially null.
num y; // Declare y, initially null.
num z = 0; // Declare z, initially 0.
}
すべての初期化されていないインスタンス変数は値nullを持つ。
すべてのインスタンス変数は暗黙的にゲッターメソッドを生成する。非finalインスタンス変数は暗黙的にセッターメソッドを生成する。詳しくはゲッターとセッターで。 code:dart
class Point {
num x;
num y;
}
void main() {
var point = Point();
point.x = 4; // Use the setter method for x.
assert(point.x == 4); // Use the getter method for x.
assert(point.y == null); // Values default to null.
}
もし宣言されたインスタンス変数を初期化するなら、値はインスタンスが作られる時に設定される。
コンストラクタ
クラスと同じ名前の関数を作ることでコンストラクタを宣言すること。コンストラクターの一般的な形式はクラスの新しいインスタンスを作る:
code:dart
class Point {
num x, y;
Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}
thisキーワードは現在のインスタンスを参照する。
インスタンス変数の配置しているコンストラクター引数のパターンはとても一般的で、Dartは簡単にするシンタックスシュガーを持つ:
code:dart
class Point {
num x, y;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
デフォルトコンストラクター
もしコンストラクターを宣言しない場合、デフォルトコンストラクターが提供される。デフォルトコンストラクターは引数を持たず、スーパークラスの引数なしのコンストラクターを呼び出す。
コンストラクターは継承されない
サブクラスはスーパークラスからコンストラクターを継承しない。サブクラスは(引数なし、名前なし)デフォルトコンストラクターをただ一つ持つ。
Namedコンストラクター
複数コンストラクターを実装するためにnamedコンストラクターを使うこと:
code:dart
class Point {
num x, y;
Point(this.x, this.y);
// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}
もしスーパークラスで定義したnamedコンストラクターを作らせるためにサブクラスを行う場合、サブクラスのコンストラクターを実装するべき。
非デフォルトスーパークラスコンストラクターを呼び出す
デフォルトで、サブクラスのコンストラクターはスーパークラスの名前なし、引数なしコンストラクターを呼び出す。スーパークラスのコンストラクターはコンストラクターの初めで呼び出される。もし初期化リストが使われているなら、スーパークラスが呼び出される前に実行する。実行順序は: 1. 初期化リスト
2. スーパークラスの引数なしコンストラクター
3. mainクラスの引数なしコンストラクター
もしスーパークラスが名前なし、引数なしコンストラクターを持たない場合、スーパークラスでコンストラクターの1つを手動で呼び出す。コロン(:)の後でスーパークラスコンストラクターを指定すること。
スーパークラスコンストラクターの引数はコンストラクターを呼び出す前に評価されるので、引数は関数呼び出しのような表現ができる:
code:dart
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}
スーパークラスコンストラクターの引数はthisへのアクセスを持たない。
初期化リスト
スーパークラスコンストラクターを呼び出すことで、コンストラクターが起動する前にインスタンス変数を初期化することもできる。コンマで初期化を分けること。
code:dart
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
print('In Point.fromJson(): ($x, $y)');
}
初期化の右側はthisのアクセスを持たない
初期化リストのassertを使うことで入力を検証できる。
code:dart
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
リダイレクトコンストラクター
コンストラクターの目的は同じクラスの他のコンストラクターにリダイレクトするため。リダイレクトコンストラクターは空である。
code:dart
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
定数コンストラクター
constコンストラクターを定義して、すべてのインスタンス変数がfinalであることを確かめること。
code:dart
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
ファクトリーコンストラクター
クラスの新しいインスタンスを常に作らないコンストラクタを実装するときにfactoryキーワードを使うこと。
キャッシュからオブジェクトを返すファクトリーコンストラクタの例:
code:dart
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
ファクトリーコンストラクタはthisにアクセスを持たない。
メソッド
メソッドはオブジェクトのふるまいを提供する関数。
インスタンスメソッド
オブジェクトのインスタンスメソッドはインスタンスとthisにアクセスできる。以下のdistanceTo()メソッドはインスタンスメソッドの例:
code:dart
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}
ゲッターとセッター
ゲッターとセッターはオブジェクトのプロパティにアクセスする読み込みと書き込みを提供する特殊なメソッド。暗黙的にゲッターを持つインスタンス変数を最呼び出しする。getやsetキーワードを使って、ゲッターを実装することで追加のプロパティを作ることができる。
code:dart
class Rectangle {
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
ゲッターとセッターで、クライアントコードを変更せずに、後でメソッドで包むことで、インスタンス変数で始めることができる。
抽象メソッド
インターフェースを定義するが、他のクラスの実装をインスタンスに任せることで、ゲッター、セッターメソッドは抽象にすることができる。抽象メソッドは抽象クラスで唯一存在できる。 code:dart
abstract class Doer {
// Define instance variables and methods...
void doSomething(); // Define an abstract method.
}
class EffectiveDoer extends Doer {
void doSomething() {
// Provide an implementation, so the method is not abstract here...
}
}
抽象クラス
(継承できる)抽象クラスを定義するのにabstract修飾子を使うこと。抽象クラスはインターフェースを定義して使えるようにする。
抽象クラスは抽象メソッドをもつ。抽象メソッドを持つ抽象クラスを宣言する例:
code:dart
// This class is declared abstract and thus
// can't be instantiated.
abstract class AbstractContainer {
// Define constructors, fields, methods...
void updateChildren(); // Abstract method.
}
暗黙的なインターフェース
あらゆるクラスはクラスとインターフェースのすべてのインスタンスメンバーを含んでいるインターフェースを暗黙的に定義する。もしクラスBの実装を継承しないでクラスBのAPIをサポートするクラスAを作りたいなら、クラスAはBインターフェースを実装するべき。
クラスは実装で宣言して、その時インターフェースによって要求したAPIを提供することで1つ以上のインターフェースを実装する。
code:dart
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Impostor implements Person {
get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
クラスが複数のインターフェースを実装することを指定する例:
code:dart
class Point implements Comparable, Location {...}
クラスを確証する
サブクラスを作るためにextendsとスーパークラスを参照するためにsuperを使うこと:
code:dart
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
オーバーライドメンバー
サブクラスはメソッド、ゲッター、セッターをオーバーライドできる。メンバーを意図的にオーバーライドしていることを示すために@overrideアノテーションを使うことができる:
code:dart
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
オーバーライドオペレーター
以下にある演算子のオーバーライドができる。
table:dart演算子
< + | []
/ ^ []=
<= ~/ & ~
= * << ==
– % >>
!=はオーバーライドできない。
+と-演算子をオーバーライドするクラスの例:
code:dart
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown. For details, see note below.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
noSuchMethod()
コードが非拡張メソッドもしくはインスタンス変数を使おうとするどんな時でも検出したり、反応するために、noSuchMethod()をオーバーライドすることができる:
code:dart
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
以下の項目に1つでも当てはまらない限り、実装されていないメソッドを呼び出すことができない:
レシーバーはstatic型dynamicをもつ。
レシーバーは実装されないメソッド(抽象はOK)を定義するstatic型を持ち、レシーバーのdynamic型はクラスObjectの1つから異なるnoSuchMethod()の実装を持つ。
列挙された型
( enumerationsまたはenumsとたびたび呼ばれる)列挙された型は修正された定数値の数を表すために使った特別なクラス。
enumを使う
enumキーワードを使って列挙された型を宣言すること:
code:dart
enum Color { red, green, blue }
enumの値はindexゲッターを持つ。enum宣言で0から始まる値を返す。初めの値はインデックス0で、2番目の値はインデックス1を持つ例:
code:dart
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
enumのすべての値のリストを手に入れるために、enumのvalue定数を使うこと:
code:dart
List<Color> colors = Color.values;
assert(colors2 == Color.blue); code:dart
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}
列挙された型は以下の制限がある:
サブクラス、ミックスイン、enumを実装できない。
enumをインスタンス化できない。
クラスの特徴を加える:ミックスイン
ミックスインは複数クラス階層でクラスのコードを再利用するための方法。
ミックスインを使うために、一つ以上のミックスイン名でwithキーワードを使うこと:
code:dart
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
ミックスインを実装するために、オブジェクトを作り、コンストラクタのない宣言をするクラスを作ること。ミックスインを通常のクラスとして使用をしたくない時以外、classの代わりにmixinキーワードを使用すること:
code:dart
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
型がミックスインを使うことができることを特定するために、要求されたスーパークラスを特定するためにonを使うこと:
code:dart
mixin MusicalPerformer on Musician {
// ···
}
mixinキーワードのサポートはDart 2.1で紹介された。より簡単なリリースのコードはabstract classの代わりに有効に使われる。詳細はとを見ること。 クラス変数とメソッド
クラスワイド変数とメソッドを実装するstaticキーワードを使うこと。
static変数
static変数(クラス変数)はクラスワイド状態や定数を有効にする:
code:dart
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
static変数は使うまで初期化されない。
staticメソッド(クラスメソッド)はインスタンス上で動作しないので、thisへのアクセスを持たない。例:
code:dart
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
ジェネリック
<...>記法はジェネリック型としてリストにマークする。
なぜジェネリックを使うのか?
ジェネリックは型安全を要求するが、以下のより多くの利点を持っている:
正しく指定しているジェネリックはよりよく生成されたコードを結果として出す。
コード重複を減らすためにジェネリックを使うことができる。
もしstringのみのリストを意図している場合、List<String>として宣言できる。仲間のプログラマーにリストが間違えるstringではない型を配置することを検出することができる。
code:dart
var names = List<String>();
names.add(42); // Error
コレクションリテラルを使う
list、set、mapリテラルはパラメータ化できる。パラメータ化されたリテラルは、<type>(リストとセットの場合)または<keyType、valueType>(マップの場合)を開始角かっこの前に追加することを除いて、すでに見たリテラルと同じ。
code:dart
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
コンストラクタのパラメータ化された型をつかうこと
コンストラクタを使うときに一つ以上の型を特定するために、クラス名の後に角括弧(<...>)の型を入れること。
code:dart
var nameSet = Set<String>.from(names);
ジェネリックコレクションと型
dartジェネリック型は具現化される。ランタイムでの型情報を運ぶという意味。
例えば、
code:dart
var names = List<String>();
print(names is List<String>); // true
パラメータ化された型を制限する
ジェネリック型を実装しているときに、パラメーターの型を制限したいかもしれない。extendsを使うことですることができる。
code:dart
class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}
それはSomeBaseClassもしくはジェネリック引数としてサブクラスを使うためにOK:
code:dart
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
ジェネリック引数を使わないで特定するためにもOK:
code:dart
var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'
SomeBaseClass型を特定することはエラーを結果として出す:
code:dart
var foo = Foo<Object>();
ジェネリックメソッドを使う
初めに、Dartのジェネリックサポートはクラスを制限させる。ジェネリックメソッドを呼んで、より新しい構文はメソッドと関数上の型引数を与える:
code:dart
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
// Do some additional checking or processing...
return tmp;
}
first (<T>) 上のジェネリック型パラメーターはたくさんの場所で型引数Tを使わせる:
関数の返す型(T)
引数の型(List<T>)
ローカル変数の型(T tmp)