June 30, 2024

Kotlinのas?はDartだとどう書くか

Kotlinの as? 便利ですよね。
hogeがHoge型の値ならresultはHogeとして認識され、たとえばStringなど別の型だった場合はnullとして扱われます。

class Hoge

val result: Hoge? = hoge as? Hoge 

Dartにも as はあるのですが、Kotlinのように as? と書くことはできずに、単純なキャストとしての役割になっています。

class Hoge {}
final hoge = "hoge";
hoge as Hoge?; // TypeError

早速ですが、Dartだとどのように書くのかを解説していきます。

  • チェック用クラス
abstract class Hoge {}

class Foo extends Hoge {
  final name = 'foo';

  void foo() {
    print('result: foo');
  }
}

class Bar extends Hoge {
  final name = 'bar';
  final baz = 100;

  void bar() {
    print('result: bar');
  }
}

1番簡単なのはif文内でcase式を使うやり方です。 これはDart3.0で導入されました。
この書き方ならば、hogeがnullの時にif文はfalseになるのでKotlinのas? と同様の効果が得られます。
これだとif文の中でしかsmart castされませんが、早期returnにすれば以降の文でもsmart castされます。


final Hoge? hoge = Foo();

if(hoge case final Foo foo) {
  foo.foo();
}

// result: foo

if文だけでなく、switch文でも書けます。
as?のように型マッチを調べるだけの用途からは脱線しましたが、複数パターンの型を1度に調べられるので、実際のプロダクト開発では頻出するパターンかなと思います。


final Hoge? hoge = Foo();

switch (hoge) {
  case final Foo foo:
    foo.foo();
  case final Bar bar:
    bar.bar();
  default:
    print('undefined');
}

// result: foo

Dart3.0からswitchは式でも表せるようになったので、そのまま値を代入することもできます。


final Hoge? hoge = Bar();

final result = switch (hoge) {
  final Foo foo => foo.name,
  final Bar bar => '${bar.name}, ${bar.baz}',
  _ => 'undefined'
};

print(result); // bar, 100

今までのDartっぽくない書き方もできて、このようにswitch内で新たに変数名を定義してあげることもできます。


final Hoge? hoge = Bar();

final result = switch (hoge) {
  Foo(name: final n) => n,
  Bar(name: final n, baz: final b) => '$n, $b',
  _ => 'undefined'
};

print(result); // bar, 100

本題とは逸れますが、switch同様にifでもこのように書き換え可能です。 プロパティも全て書く必要がないので、条件式内で利用するものだけ書くと結構便利です。

if (hoge case Bar(baz: final b)) {
  print(b);
}

まとめ

Dart3.0になってからは as? 相当の書き方も便利になり、かなり書き方の自由度が増えた感じがします。
もはやas?を足して欲しい気もしますが、現状でも充分使えると思います。

Dart3.0で便利になったSwitchの使い方はこちら にまとめているので興味がある方はご覧ください。

© AAkira 2023