前のページ

言語編

次のページ


組み込み型(Built-in Types)

Dart言語は以下の型に対して特別なサポートをしている:

  • 数値(numbers)

  • 文字列(strings)

  • ブール値(booleans

  • リスト(lists)(アレー(arrays)としても知られる)

  • マップ(maps)

  • ルーン文字(runes) (文字列内のUnicoode文字の表現用)

  • シンボル(symbols)

これらはDartcoreライブラリに収容されており、詳細はDartAPI参照を見て頂きたい。

これらの型たちのオブジェクトはリテラルを使って初期化できる。例えば、'this is a string'は文字列のリテラルであり、またtrueはブール値のリテラルである。

Dartでは各変数はあるオブジェクト(あるクラスのインスタンス)を参照しているので、変数を初期化するには通常コンストラクタが使える。組込み型のあるものはそれ自身のコンストラクタを有している。例えば、マップを生成するにはMap()コンストラクタが使える。



数値(numbers)

Dartには下図のように64ビットの2の補数方式の固定小数点であるint(但しJavaScriptでのビット演算は32ビット)と、64ビット倍精度浮動小数点のdouble2つが用意されている。これらはともにnumという抽象クラスを実装している。numはまたComparableインターフェイスを実装している。




Int

整数の値はプラットホームに依存し、64ビットまたはそれ以下の値である。Dart VM上では、その値は-263 から 263 - 1の範囲となる。 JavaScriptに変換されたDartJavaScriptの数値を使用していて、-253 から 263 – 1の値が許される。

注意:JavaScriptに変換されたDartコードの場合は、整数は倍精度浮動小数点値で表現されうる値に制限される。従って使える整数は -2^53 2^53 の範囲及びより大きな値の一部の整数(これには一部の2^63より大きな数が含まれる)である。従ってintクラスの演算子とメソッドの振る舞いはDart VMJavaScriptにコンパイルされたDartコードとでは差が生じることがある。例えば、JavaScriptにコンパイルされたときはビット演算子は32ビットの整数に切り捨てられる。

double

IEEE 754標準で規定されている64ビットの不動小数点の数値である。なお0.0/0.0は浮動小数点の数字ではないのでNAN(Not a number)という扱いになる。それ以外の0での除算はプラスまたはマイナスの無限大(Infinity)になる。:

main() {
  double x = double.nan;
  double y = 1.0;
  print("${x.isNaN}, ${y.isNaN}");
  double z = 0/0;
  print("$z, ${z.isNaN}");
  var p = 1/0;
  var q = -1/0;
  print("$p, $q");
}
/*
true, false
NaN, true
Infinity, -Infinity
*/



num

intdoubleの双方はnumのサブタイプである。従って数値変数を宣言するときはintdouble、あるいはそのどちらかでも良いときはnumという型指定を行う。

import 'dart:math';
num numval = pi;
main() {
  int intval = numval + 5; // Error : double is not assignable to int
  print(intval);
}
/*
8.141592653589793
*/

この例の4行目のintvalに対するint指定はエラーとなる。従ってdoublenumまたはvarで宣言しなければならない。

num型は+, -, /, 及び *といった基本的な演算子を含んでおり、またabs(), ceil(), 及び floor()などといったメソッドが存在する。(>>などのビット単位演算子はintクラスの中で定義されている。)numとその副型に自分が探しているものがないときはdart:mathライブラリにある可能性もある。

以下はnumクラスのなかのメソッドから有用と思われるものである:

main() {
  // 絶対値
  assert((-4).abs() == 4);
  // 切り上げときり下げ
  assert(3.14.ceil() == 4.0);
  assert(3.14.floor() == 3.0);
  // 四捨五入
  assert(3.14.round() == 3);
  assert(3.54.round() == 4);
  assert(3.5.round() == 4);
  assert(3.49.round() == 3);
  // 切り捨て
  assert(3.141592.truncate() == 3.0);
  // doubleからintへの変換
  assert(3.14.toInt() == 3);
}



数値の使用例

整数は小数点のない数である。以下に整数リテラルを定義している幾つかの例を示す:

var x = 1;
var hex = 0xDEADBEEF;

小数点が含まれる数はdoubleである。以下にdoubleのリテラルを定義している幾つかの例を示す:

var y = 1.1;
var exponents = 1.42e5;

Dart 2.1時点では、整数リテラルは必要に応じ自動的にdoubleに変換される:

double z = 1; // z = 1.0と等価

バージョン版に関して: Dart 2.1版以前ではdoubleのコンテキスト内で整数リテラルを使うのはエラーだった。

以下は文字列と数値の変換例である:

// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

int型では一般的なビット単位の演算子であるシフト(<<, >>)and(&)、及びor(|)が規定されている。例えば:

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111

リテラル数はコンパイル時常数である。多くの代数式もまた、その被演算物が数に計算されるコンパイル時常数である限りコンパイル時常数である。

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;



文字列(String)

Dartの文字列はUTF-16コード単位の並びである。文字列を生成するのにはシングル・クオートまたはダブル・クオートのいずれかが使える:

var s1 = 'Single quotes work well for string literals.';  // シングル・クオート
var s2 = "Double quotes work just as well.";  // ダブル・クオート
var s3 = 'It\'s easy to escape the string delimiter.';    // 終端文字のエスケープ
var s4 = "It's even easier to use the other delimiter.";  // 別の終端文字を使ったほうがもっと簡単

${}を使ってある文字列内にある式の値を置くことができる。これは文字列内挿(string interpolation)とも呼ばれる。もしその式がある識別子であるときは{}をスキップできる。あるオブジェクトに対応した文字列を取得する為、DartはそのオブジェクトのtoString()メソッドを呼ぶ。

var s = 'string interpolation';
assert('Dart has $s, which is very handy.' ==
'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');

注意:==演算子はふたつのオブジェクトが等価であるかどうかをテストする。2つのオブジェクトの中身がコード単位で同じシーケンスであるときは等価である。

隣接文字列リテラルまたは+演算子を使って文字列を連結できる:

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');  // 改行があっても文字列連結は機能する
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');

複行文字列を生成する別の手段:シングル・クオートまたはダブル・クオートのマークによるトリプル・クオートを使用する:

var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";

rをプレフィックスとして付すことで「生」文字列を生成できる:

var s = r'In a raw string, not even \n gets special treatment.';

文字列内のUnicode文字の表現法の詳細はRunesを見られたい。

内挿された式がリテラル文字列、nullまたは数値、文字列、またはブール値として計算されるコンパイル時常数である限り、リテラル文字列はコンパイル時常数である。

// これらはconst文字列として機能する
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// これらはconst文字列として機能しない
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

文字列の使用に関しては「Stringsと正規表現」を参照されたい。



ブール値(booleans

ブール値を表現する為に、Dartboolと称する型を有している。型boolには2つのオブジェクトのみがある:ブール値リテラルのtruefalseのであり、その双方はコンパイル時常数である。

Dartが型安全だということは、if (nonbooleanValue)またはassert (nonbooleanValue)のようなコードは書けないということである。その代わりとして以下のように明示的に値をチェックことになる:

// 空の文字列のチェック
var fullName = '';
assert(fullName.isEmpty);
// ゼロのチェック
var hitPoints = 0;
assert(hitPoints <= 0);
// nullのチェック
var unicorn;
assert(unicorn == null);
// NaNのチェック
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);



リスト(Lists)

おそらく殆どのプログラミング言語で最も共通的なコレクションはアレイ、または順序付けられたオブジェクトのグループであろう。DartではアレイはListオブジェクトであり、殆どの人たちは単にリストと呼んでいる。

Dartのリスト・リテラルはJavaScriptのアレイ・リテラルと似ている。以下はシンプルなDartのリストである。

var list = [1, 2, 3];

注意:Dartのアナライザはこのリストは型List<int>だと推論する。このリストに非整数のオブジェクトを追加しようとすると、アナライザあるいはランタイムがエラーを生起する。より詳細は型推論に関する記事を読まれたい。

リストはゼロ・ベースのインデックス化を使っており、0は最初の要素のインデックスであり、list.length – 1は最後の要素のインデックスである。ちょうどJavaScriptと同じように、あるリストの長さを取得したりリスト要素を参照できる。

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);

コンパイル時常数であるリストを生成するには、このリスト・リテラルの前にconstを付加する:

var constantList = const [1, 2, 3];
// constantList[1] = 1; // コメントを外すとエラーを生じる

List型はリストの操作のための多くの便利なメソッドたちを有している。リストに関するより詳細な情報は「総称型」と「コレクション」の章を見て欲しい。

より詳細な使用法

ここからはもう少し詳しくリストの使用法を解説する。

[]はリスト・リテラルを示すことになるので、

var list = [] ;

とあるListを宣言したとすると、それは

List list = List<dynamic>();

と宣言したと等価である。

リストの全要素の型が固定されているときは例えば次のように宣言できる:

var a = <int>[0,1,2];
List<int> b;

また、

List list;

という宣言はlistという名前の宣言だけで、オブジェクトは生成されずnullであることに注意する。

List myList;
main() {
  print(myList);
//  myList.add("Hello"); // error
  myList = List();
  print(myList.length);
  myList.add("Hello");
  print(myList);
  print(myList.length);
}
/*
null
0
[Hello]
1
*/
  • 最初のList myList;は変数を定義しただけで、オブジェクトは生成されない。従ってこれはnullと出力される。

  • nullのオブジェクトに対しては、myList.add("Hello");という操作はできない(NullPointerExceptionが生起される)。

  • myList = List();はコンストラクタを呼びオブジェクトが生成される。ここでは長さが0のオブジェクトである。これはvar myList[];あるいはList myList = [];という記述でも同じ効果を持つ。

  • これに対してはmyList.add("Hello");という操作が可能になる。

次の例では:

import 'dart:math';
main() {
  List myList = ['pi is ', pi, ', and cos pi is ', cos(pi)];
  String s = '';
  for (int i = 0; i < myList.length; i++) {
    s = "$s${myList[i].toString()}";
  }
  print(s);
}
/*
pi is 3.141592653589793, and cos pi is -1
*/
  • この例ではmyListというリストに2つの文字列と2つのdoubleの値が最初に含められている。

  • sという変数はなにもセットしないとnullのままなので、初期値として空の文字列''をセットする。空の文字列はnullではないので、他の文字列を連結させることができる。

  • リストの中身のインデックスは0から始まるので最後の値はmyList.lengthになる。

  • 総てのオブジェクトのもとになっているObjectにはtoStringメソッドが定義されているので、これを使って総ての要素を文字列に変換して連結させている。但しDarttoString()を付けなくても自分で判断してtoString()を呼び出す。各自確認されたい。

文字列が要素であるListのソーティングの例を次に示す。StringComparable<String>を実装しているので、比較を使ったソートが簡単に実現できる:

main() {
  List<String> list = ['安部', '97', '01', 'abcd', 'ABcd', '安部晋一郎'];
  list.sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
  list.forEach((s) {
    print(s);
  });
}
/*
01
97
abcd
ABcd
安部
安部晋一郎
*/

ListIterableを実装しているのでこのようにforEachメソッドが使える。4行目のprintの箇所は次のように記述できる:

list.forEach(print);

比較関数としてcompareToが使われている。toLowerCaseで一旦小文字にして比較するのは、同じ英文字の大文字と小文字では大文字のコードが小さいので、'Zabc''aabc'よりも若くなってしまい、見づらくなる為である。このような使い方はComparableを実装しているBigInt, DateTime, Duration, num, Stringに適用できる。

ListCollectionを実装しているので、このメソッドのreduceを使ってリストの中から最大または最小の要素をとりだすことも出来る。

import 'dart:math' as Math;
main () {
  var a = [7, 2, 4, 1, 9];
  print(a.reduce(Math.min)); // 1
  print(a.reduce(Math.max)); // 9
}



バイト列

バイト列はネットワークを介したデータ交換やファイル・データの取り扱いに良く使われるが、リストはバイト列を表現するのにも良く使われる。

import 'dart:convert';
main() {
  var string = 'Dart言語';
  List<int> bytes = [];
  bytes.addAll(new Utf8Codec().encode(string));
  print(bytes);
}
// [68, 97, 114, 116, 232, 168, 128, 232, 170, 158]

これは'Dart言語'という文字列をUTF-8のバイト列に変換したものである。このようにbytesというバイト列はバイト(8ビット即ち0から255までの整数)の列になっている。



マップ(Maps

一般的に、マップはキー(keys)と値(values)を結び付けたオブジェクトである。キーと値の双方ともどの型のオブジェクトでもなり得る。各キーはただ1回生じるが、同じ値を複数回使うことは可能である。Dartのマップはマップ・リテラルとMap型でサポートされている。

以下では2つのシンプルなDartのマップがマップ・リテラルにより生成されている:

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};
var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

注意:アナライザはgiftsが型Map<String, String>でありnobleGasesMap<int, String>だと推論する。いづれかのマップに対し間違った型の値を追加しようとすると、アナライザとランタイムはエラーを生起する。より詳細は型推論を読まれたい。

JavaScriptと同様に、既存のマップに新たなキー-値のペアを追加する:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 新たなkey-valueペアを追加する

マップから値を取り出すのもJavaScriptと同様である:

var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

マップ内に無いキーを探そうとすると、戻り値にはnullが入る:

var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

-値のペアの数を取得するには.lengthを使用する:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

コンパイル時常数であるマップを生成するには、そのマップ・リテラルの前にconstを付加する:

final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};
// constantMap[2] = 'Helium'; // ここのコメントを外すとエラーを起こす

マップに対するより詳細は総称型Mapを参照されたい。



より詳細な使用法

{}はマップ・リテラルを示すことになるので、

var map = {} ;

とあるMapを宣言したとすると、それは

Map map = Map<String, dynamic>();

と宣言したと等価である。

また、

Map map;

という宣言はmapという名前の宣言だけで、オブジェクトは生成されずnullであることに注意されたい。

簡単な番号案内のプログラムを示す:

main() {
  Map directory = const {
    'fire': 119,
    'cops': 110,
    'emergency': 120,
    'time': 117
  };
  String s = 'time';
  if (directory.containsKey(s))
    print('$s? dial ${directory[s]}');
  else
    print('sorry, no number available for $s');
}
/*
time? dial 117
*/
  • Map型の電話帳であるdirectoryStringの電話先とintの電話番号からなる。(この例では0から始まる番号は扱えない)

  • containsKey(s)というメソッドは指定したキーが存在するかどうかをboolで返す。

  • [s]という演算子は指定したキーの値を返す。

MapK, V>の詳細はMapAPI参照を見て頂きたいが、幾つかのメソッドとプロパティの使い方を示す:

main() {
  var directory = {'fire': 119, 'cops': 110, 'emergency': 120, 'time': 117};
  directory['weather'] = 177;    // 要素の追加
  print(directory['weather']);   // 177
  print(directory.length);       // 5, キーと値のペアの数
  directory.remove('weather');   // 要素の削除
  print(directory.length);       // 4
  print(directory['weather']);   // null
  directory.forEach((k,v) => print(k));  // 繰り返し操作
  directory.putIfAbsent('earthquake', () {
    // do something
    return 171;
  });
  print(directory['earthquake'] );       // 171
}
/*
 * 177
5
4
null
fire
cops
emergency
time
171
*/



MapJSON

DartではMapで記述したオブジェクトはJSONテキストと同じになる。dart:convertにはトップ・レベルの常数としてjsonが存在し、これはJsonCodecのデフォルト実装のインスタンスである。これを使ってMapの内容とJsonの文字列との変換を可能としている:

import 'dart:convert';
var jsonObj = {
  "language": "DART",
  "targets": ["dartium", "javascript", "Android?"],
  "website": {"homepage": "www.dartlang.org", "api": "api.dartlang.org"}
};
var jsonStr = '''{"language":"DART",
    "targets":["dartium","javascript","Android?"],
    "website":{"homepage":"www.dartlang.org","api":"api.dartlang.org"}}
''';
main() {
  String jsonString = json.encode(jsonObj);
  print('encoded JSON string : \n$jsonString');
  var jsonObject = json.decode(jsonStr);
  print('decoded JSON object : \n$jsonObject');
  print('is type of the JSON object Map? : ${jsonObject is Map}');
}

この結果はDartPadで確認されたい。このマップ(jsonObj)"language"(文字列)、"targets"(リスト)、及び"website"(マップ)の3つの要素からなっている。これをjson.encodeメソッドを使ってJSONの文字列に変換したjsonStringも全く同じ文字列となる。ここでは逆にjson.decodeメソッドを使ってJSON文字列をMap型のオブジェクトに変換することも行っている。

このMapオブジェクトの各要素に対しては

jsonObj["website"]["homepage"]

というアクセスはできるが、通常のクラス・メンバのような

jsonObj.website.homepage

というようなアクセスは出来ない。

より詳細はライブラリ編の「dart:convertに記されている。



ルーン文字(Runes)

Dartでは、ルーン文字はある文字列のUTF-32コード・ポイントである。

ユニコード(unicode)では世界中の綴字法システムで使われている文字、数字、及びシンボルの各々に対する数値を定めている。Dartの文字列はUTF-16コード単位の並びであるので、32ビットのUnicode値を文字列内で表現するには特別の文法が必要になる。

Unicodeコードポイントの通常の表現法は\uXXXXで、ここにXXXXは4桁の16進数である。例えば、ハート文字(♥)\u2665である。16進数の4桁以上または4桁以下のものを指定するときは、その値を中括弧で囲む。例えば、笑い文字(😆)\u{1f600}である。

ルーン文字を情報を抽出できる幾つかのプロパティがStringクラスにある。codeUnitAtcodeUnitプロパティは16ビットのコード・ユニットを返す。ある文字列からルーン文字を取得するのにはrunesを使う。

次の例はルーン文字、16ビットのコード・ポイント、及び32ビットのコード・ポイント間の相互関係を示している。

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());
  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}

このコードはDartPadで試すと良い。

注意:リストの操作でルーン文字を操作するのは注意を要する。このアプローチはとりわけ言語、文字セット、そして操作に依存して容易に失敗しうる。詳細はStack Overflow上のHow do I reverse a String in Dart?を見て欲しい。



シンボル(Symbols)

SymbolオブジェクトはあるDartのプログラムの中で宣言された演算子または識別子を表現している。シンボルを使う必要は絶対出てこないかもしれないが、縮小化(minification)が識別子名を変えるが識別子のシンボルたちを変えないので、これらは名前によって識別子を参照するAPIでは貴重である。

ある識別子のシンボルを取得するには、シンボル・リテラル使用する。これは#の後に識別子を置いたものである:

#radix
#bar

Symbolリテラルはコンパイル時常数である。





前のページ

次のページ