88
63

More than 5 years have passed since last update.

【翻訳記事】なぜFlutterにおいてDartを使用するのか?

Last updated at Posted at 2018-10-12

はじめに

当記事は「Why Flutter Uses Dart」を翻訳したものです。

昨日は「What’s Revolutionary about Flutter」の翻訳記事において、Flutterクロスプラットフォームにおける技術的優位性(Web系フレームワーク、React系と比べて)を記述しましたが、本日はFlutterアプリのプログラム言語であるDartについて掘り下げてみました。

重厚長大な言語を巡る旅です。読んでいて楽しかったです。

当記事においても、誤訳・ご指摘などあれば教えていただけると幸いです。

Why Flutter Uses Dart?

多くの言語学者は、「人が話す言語は自分の考え方に影響を与える」と考えています。同じ概念がプログラム言語にも当てはまりますか?異なる種類のプログラム言語を使用するプログラマーは、問題においてしばしば根本的に異なる解決策を考え出します。より極端な例として、コンピュータ科学者は、より構造化されたプログラムを奨励するためにgotoステートメントを削除しました(小説「1984年」の全体主義者の思想犯罪者を排除した例(=言論統制)とは全く異なりますが、着想は得られます。

これはFlutterとDartとは何か関係がありますか?少しはあります。 Flutterの初期チームは数十を超える言語を評価し、ユーザーインターフェイスを構築する方法と一致しているためにDart言語を選択したのです。

Dartは、開発者がFlutterを愛する大きな理由です。 1つのTweetを引用しますと、

@flutterio got me to look at @dart, and I’m glad I took it for a spin. #Dart is an awesome language, and #flutterio takes it even further, to mobile devices
意訳:Dartすげー!flutterioがdart進化させたじゃん!

Flutterのために必要不可欠なDart機能の一覧は以下です。

  • Dartは速く,予測可能なネイティブコードにコンパイルされたAOT(Ahead Of Time)で、FlutterのほぼすべてをDartで書くことができます。
  • Dartは、非常に高速な開発サイクルとゲーム感覚のワークフロー(Flutterの標準の秒速でのステートフルなホットリロードを含む)用にコンパイルされたJIT(Just In Time)でもあります。
  • Dartでは、60fpsで動作する滑らかなアニメーションやトランジションを簡単に作成できます。Dartは、ロックなしでオブジェクトの割り当てとガベージコレクションを実行できます。 JavaScriptのように、Dartはpree,ptive schedulingと共有メモリ(したがってロック)を回避します。 Flutterアプリケーションはネイティブコードにコンパイルされているため、レルム間のbrigeを必要としません(JavaScriptからネイティブなど)。また、はるかに速く起動します。
  • Dartの宣言的なレイアウトは読みやすく、視覚化しやすいため、Dartを使用すると、FlutterはJSXやXMLなどの宣言的なレイアウト言語や別のビジュアルIFビルダーの必要性を減らせます。 Flutterでは、すべてのレイアウトを1つの言語と1か所で簡単に実行できるため、高度なツールを使用してレイアウトを簡単に行うことができます。
  • 開発者は、Dartは、静的言語と動的言語の両方のユーザーにとって使い慣れた機能を備えているため、特に学習が簡単であることを発見しました。

これらの機能のすべてがDartに固有のものではありませんが、それらの組み合わせは、Flutterを実装するためのDartを独自の強力にします。Dartがなければ、Flutterは強力であることは難しいです。

1_bAUFoOPQ3gcv7y4Kdz82tw.png

この記事では、Flutterを実装するための最良言語のDart(標準ライブラリを含む)の多くの特徴について深く説明します。

Compilation and execution(コンパイルと実行)

[静的対動的言語、AOTおよびJITコンパイル、仮想マシンなどのトピックについて既に知っている場合は、このセクションをスキップできます。]

従来、コンピュータ言語は、静的言語(コンパイル時に変数が静的に型付けされる言語:Fortran,C)と、動的言語(実行時に変数の型が変更される言語:Smalltalk,JavaScript)の2つのグループに分かれていました。静的言語は、通常、実行時にハードウェアによって直接実行されるターゲットマシン用のネイティブマシンコード(またはアセンブリコード)プログラムを生成するようにコンパイルされました。動的言語は、機械語コードを生成することなく、インタプリタによって実行されました。

もちろん、区分はもっと複雑になりました。仮想マシン(VM)の概念の普及です。これは実際はソフトウェアのハードウェアマシンを模倣した高度なインタプリタです。仮想マシンを使用すると、新しいハードウェアプラットフォームに言語を移植することが容易になります。この場合、VMの入力言語はしばしば中間言語です。たとえば、プログラミング言語(Javaなど)は中間言語(バイトコード)にコンパイルされ、VM(JVM)上で実行されます。

さらに、ジャストインタイム(JIT)コンパイラも存在します。 JITコンパイラはプログラムの実行中に実行され、即時コンパイルされます。プログラムの作成中(実行前)に実行される元のコンパイラは、AOT(Ahead-Of-Time)コンパイラと呼ばれるようになりました。

一般に、機械語は一般的にデータの種類を知る必要があるために、静的言語のみがAOTコンパイルの対象となります。動的言語ではその型が事前に固定されていないため違います。したがって、動的言語は通常、解釈されるか、またはJITコンパイルされます。

開発中にAOTコンパイルが行われると、開発サイクルがずっと遅くなります(プログラムを変更してからプログラムを実行して変更の結果を確認するまでの時間がです)。しかし、AOTのコンパイルにより、一時停止して分析することなく即時の予測が可能になりました。 AOTコンパイルされたプログラムも(すでにコンパイルされているため)より高速に実行を開始します。

逆に、JITコンパイルでは開発サイクルがはるかに高速になりますが、実行速度が遅くなったり不安定になる可能性があります。特に、JITコンパイラの起動時間が遅くなるのは、プログラムの実行開始時にJITコンパイラがコードを実行する前に解析とコンパイルを行う必要があるためです。いくつかの調査によると、実行を開始するには数秒以上かかると多くの人がアプリを使わないことが示されています。

以上が理論的な背景の説明です。 AOTとJITの両方のコンパイルの利点を組み合わせられたのならばすばらしいではないでしょうか?

Compiling and executing Dart(Dartのコンパイルと実行)

Dartの開発メンバーは動的言語と静的言語の両方で高度なコンパイラと仮想マシンの画期的な作業を行っていました。彼らはこの経験を使って、Dartをコンパイルして実行する方法に柔軟に対応しました。

Dartは、AOTとJITの両方をコンパイルするのに非常に適した言語(そしておそらく唯一の「主流」言語)の1つです。両方の種類のコンパイルをサポートすることで、Dartと(特に)Flutterに大きな利点をもたらします。

JITコンパイルは、特に高速なコンパイラが開発中に使用されます。そしてアプリのリリースの準備ができたら、やがてAOTコンパイルされます。その結果、高度なツールやコンパイラの助けを経ることで、Dartは非常に速い開発サイクルと迅速な実行と起動時間の両方を実現できます。

Dartのコンパイルと実行の柔軟性はこれに留まりません。例えば、DartはJavaScriptでコンパイルできるので、ブラウザで実行できます。これにより、モバイルアプリとウェブアプリの間でコードを再利用することができます。モバイルアプリとウェブアプリの間で最大70%のコード再利用が可能との報告があります。Dartは、ネイティブコードにコンパイルするか、JavaScriptにコンパイルしてnode.jsとともに使用することによって、サーバー上で使用することも可能です。

最後に、Dartは、Dart言語自体を中間言語として使用するスタンドアローンVMも提供します(本質的にインタープリタのように機能します)。

Dartは効率的にAOTやJITをコンパイルしたり、解釈したり、他の言語に翻訳することができます。 Dartのコンパイルと実行は非常に柔軟であるだけでなく、特に高速です。

次章では、Dartのコンパイル速度を革新的に変化させる(can be a game changer)方法の例を紹介します。

Stateful hot reload

Flutterの最も一般的な機能の1つは、非常に高速なホットリロードです。開発中、FlutterはJITコンパイラを使用して、通常は1秒以内にコードをリロードして実行を継続できます。可能であれば、アプリケーションの状態はリロードを超えて保持されるため、アプリケーションは中断していた場所から続けることができます。

あなたは自分で経験しない限り、ホットリロードがいかに重要であるかを理解するのは難しいです。開発者は、アプリを作成する方法を変え、アプリを生き生きと描写すると報告しています。

Flutterのホットリロードについて、モバイルアプリの開発者は以下のように述べています

I wanted to test the hot reloading, so I changed a color, saved my modification, and… fell in love ❤️!
This feature is really amazing. I thought the Edit & Continue in Visual Studio was good, but this is simply astounding. Only with this, I think a mobile developer can be two times more productive.
This is really a game changer for me. When I deploy my code and it takes a long time, I lose my focus, I do something else and when I come back to the simulator/device I have lost track of what I wanted to test. What’s more frustrating than losing 5 minutes to move a control by 2px? With Flutter this no longer exists.

意訳:HotReloadすげー!

Flutterのホットリロードにより、新しいアイデアを試したり、代替案を試したりするのがはるかに簡単になり、創造性が大幅に向上します。

ここまでは、Dartが開発者にとってより良いものになる方法についての説明です。次章では、Dartによってユーザーを楽しませるスムーズなアプリを簡単に作成する方法についての説明です。

Avoiding jank(ガチャガチャ(?)を避ける)

高速なアプリは素晴らしいですが、スムーズなアプリはより優れています。例え高速であれ、それがガチャガチャであれば悪く見えます。しかし、あまりにも多くの異なる原因があるので、ジャンクを防ぐことは難しいかもしれません。ダーツには、ジャンクを引き起こす一般的な事柄の多くを避けるためにいくつかの機能があります。

AOT compilation and the “bridge”(AOTコンパイルとブリッジ)

私たちは既に物事をスムーズにするのに役立つ機能について議論しました。それはAOTをネイティブマシンコードにコンパイルするDartの力です。事前コンパイルされたAOTコードは、実行時にJIT分析またはコンパイルを実行するための休止がないため、JITよりも予測可能です。

しかし、AOTコンパイルされたコードにはさらに大きな利点があり、それは "JavaScriptブリッジ"の使用を避けたことです。動的な言語(JavaScriptなど)がプラットフォーム上のネイティブコードと相互運用する必要がある場合は、ブリッジを介して通信する必要があります。そのため、特に大量の状態(潜在的には二次ストレージ)を節約する必要があります。これらの切り替えは、動作が遅いのみならず、深刻なジャンクを引き起こす可能性があるため、二重に邪魔です。
ContextSwitch.png
Note:コンパイルされたコードでも、プラットフォーム側のコードとの対話用のインターフェイスが必要な場合があります。これもまたブリッジと呼ばれますが、通常は動的言語で必要なブリッジよりも数桁早いです。さらに、Dartはウィジェットのようなものをアプリ側に移すことができるため、ブリッジを通過する必要性が軽減されます。

Preemptive scheduling, time slicing, and shared resources

複数の同時実行スレッド(Java、Kotlin、Objective-C、およびSwiftを含む)をサポートするほとんどのプログラム言語は、スレッド間で切り替えを行うためにプリエンプションを使用します。各スレッドには、実行する時間の「スライス」が割り当てられ、割り当てられた時間を超えると、コンテキストスイッチを使用してスレッドがプリエンプトされます。ただし、スレッド間で共有されるリソース(メモリなど)が更新されているときにプリエンプションが発生すると、競合状態が発生します。

競合状態は、アプリをクラッシュさせたりデータを失わせたりするなど重大なバグを引き起こす可能性があり、また独立したスレッドのタイミングに依存するため、検索や修正が特に困難です。デバッガでアプリを実行すると、競合状態が発生するのを止めることは、一般的ではありません。

競合状態を修復する典型的な方法は、他のスレッドの実行を妨げるロックを使用して共有リソースを保護することですが、ロック自体がジャンクやさらに重大な問題(デッドロックや資源飢餓など)を引き起こす可能性があります。

Dartはリソース問題に対して異なるアプローチをとりました。アイソレートと呼ばれるDartのスレッドは、メモリを共有しないため、ほとんどのロックの必要はありません。アイソレートは、ErlangのアクターやJavaScriptのWebワーカーに似ている、チャネルを介してメッセージを渡すことで通信する手法です。

DartはJavaScriptのようにシングルスレッドであるため、プリエンプションができません。代わりに、明示的にスレッドを生成します(async / await、Futures、またはStreamsを使用)。これにより、開発者は実行をより詳細に制御できます。シングルスレッド化により、開発者は、重要な機能(アニメーションやトランジションを含む)がプリエンプションなしで完結して実行するになります。これは、UIだけでなく、他のコードにとっても利点です。

もちろん、開発者が制御(yield control)を忘れると、その他コードの実行が遅くします。しかし、私たちは、ロックを忘れること(forgetting to lock)より、制御(yield control)を忘れることを見つけ修正する方が簡単とわかりました。

Allocation and garbage collection(割り当てとガベージコレクション)

ジャンクのもう一つの深刻な原因はガベージコレクションです。実際、これは共有リソース(メモリ)にアクセスする特別なケースです。多くの言語ではロックを使用する必要があります。しかし、ロックによって、空きメモリが収集されている間にアプリケーション全体が実行されなくなる可能性があります。しかし、Dartはロックなしでほとんどすべての時間ガベージコレクションを実行できます。

Dartは、多くの短命(short-lived)オブジェクトを割り当てるために特に高速な、世代間のガベージコレクションと割り当てスキームを使用します(Flutterのような反応的なユーザーインターフェイスには完璧な、フレームごとに不変なビューツリーを再構築します)。Dartは、単一のpointer bump(ロックは不要)でオブジェクトを割り当てることができます。もう一度、スムーズなスクロールとアニメーションが可能になります。

Unified layout(統一的レイアウト)

Dartのもうひとつの利点は、FlutterはプログラムとJSXやXMLのような追加のテンプレートやレイアウト言語との間でレイアウトを分割したり、別々のビジュアルレイアウトツールを必要としないことです。
Dartで書かれた簡単なFlutterビューです:

hello.dart
new Center(child:
  new Column(children: [
    new Text('Hello, World!'),
    new Icon(Icons.star, color: Colors.green),
  ])
)

hello_dart.png
コードの出力を視覚的に理解することは簡単です。

FlutterはDart2を使用するのでレイアウトはさらに簡単で明確になりました(新しいキーワードはオプションであるため)。静的レイアウトは、宣言的レイアウト言語で書かれたように見えます。

hello.dart
Center(child:
  Column(children: [
    Text('Hello, World!'),
    Icon(Icons.star, color: Colors.green),
  ])
)

しかし、あなたはこう考えるでしょう - どのようにしたらレイアウト言語の欠点を利点と呼べるでしょうか?しかし、実際はとても革新的なのです。ここで、開発者が「Why native app developers should take a serious look at Flutter」という記事で書いたことを紹介します。

In Flutter, layouts are defined using Dart code only. There is no XML / templating language. There’s no visual designer/storyboarding tool either.
My hunch is, upon hearing this, a number of you might even cringe a little. Prima facie, that was my reaction too. Isn’t it easier to do layouts using a visual tool. Wouldn’t writing all kinds of constraint logic in code make things overly complicated?
The answer for me turned out to be no. And boy! what an eye opener it has been.
意訳:Flutterではレイアウトを記述するのにDartだけだそうだ!まじか!

答えは先に言及したホットリロードにあります。

I can’t stress enough how this is light years ahead of Android’s Instant Run, or any similar solution. It just works, even on large non-trivial apps. And it is crazy fast. That’s the power of Dart for you.
意訳:どんなアプリも簡単につくれるぜ!Dartってすげえや!

Dartはわかりやすいレイアウトを作成し、「狂った速さの」ホットリロードは結果を即座に見ることができます。レイアウトに非静的(non-static)な部分も含まれています。

And as a result, I have been way more productive writing layouts in Flutter (Dart) than either Android/XCode. Once you get the hang of it (for me that meant a couple of weeks), there is a substantial overhead reduction because of very little context switching that is happening. One does not have to switch to a design mode, and pick a mouse and start clicking around. And then wondering if something has to be done programmatically, how to achieve that etc. Everything is programmatic. And the APIs are very well designed. It becomes intuitive soon and is much more powerful than the constructs offered by auto layout / layout XMLs.
意訳:Android(XML),Xcode(Storyboard)よりもコードベース、APIベースのほうが良いと思うよ!

以下に、アイテム間にdivider(水平線)を追加した単純なリスト構造のプログラムを示します。

divided_list.dart
return new ListView.builder(itemBuilder: (context, i) {
  if (i.isOdd) return new Divider(); 
  // rest of function
});

Flutterでは、すべてのレイアウトは1か所に存在します(静的レイアウトかプログラムレイアウトかにかかわらず)。また、Flutter Inspectorやアウトラインビューなどのツール群は、複雑で美しいレイアウトをさらに簡単にします。

Is Dart a proprietary language?(Dartは独占的な言語か(=not open source langauge)?)

いいえ、Dart(Flutterのような)は完全なオープンソースであり、クリーンなライセンスを持っており、ECMA標準です。DartはGoogleの内外で人気があります。 Googleの中で最も急成長している言語の1つで、AdWords、Flutter、Fuchsiaなどで使用されています。 Dartリポジトリには100以上の外部コミッターも存在しています。

Dartのオープン性のさらに優れた指標は、Google以外のコミュニティの成長です。たとえば、Dart(FlutterとAngularDartを含む)に関する記事や動画が多く見られますが、この記事のいくつかはそれらを引用しています。

Dart自体の外部コミッターに加えて、Firebase、Redux、RxDart、国際化、暗号化、データベース、ルーティング、コレクションなどのライブラリを含む、パブリックなDartパッケージリポジトリは3000以上のパッケージがあります。

Will Dart programmers be hard to find?(Dartプログラマーを探すのは難しい?)

多くのプログラマーがDartを知らない場合は、適格なプログラマーを探すことが難しいでしょうか?いいえ違います。Dartは学習が簡単な言語です。実際、Java、JavaScript、Kotlin、C#、Swiftなどの言語をすでに知っているプログラマは、Dartですぐにプログラミングを開始できます。

また、「Why Flutter Will Take Off in 2018」というタイトルの記事から引用します:

Dart, the language used to develop Flutter apps, is stupid-simple to learn. Google has experience in creating simple, well documented languages like Go, for example. So far, to me, Dart reminds me of Ruby and it’s a pleasure to learn. It’s also not only for mobile but for the web as well.
意訳:GoogleはGoなど言語作成のノウハウがあるよね。DartはRubyみたいに学ぶのが楽しい言語だね。

また別の記事「Why Flutter? and not framework X? or better yet why i’m Going Flutter all in.」の引用です

Flutter uses the Dart Language that was created by google also, to be honest i’m not a fan of strongly typed languages like C# or JAVA, but i don’t know why Dart’s way of writing code seems different. And i feel very comfortable writing it. Maybe because its very simple to learn, and very straightforward.
意訳:Java,C#系と違うね。学習コストは低いね。

Dartは、豊富なUXの調査とテストを通して、習得しやすいように特別に設計されました。たとえば、2017年前半にFlutterチームは8人の開発者を持つUX調査を行いました。私たちはFlutterの短い紹介をしてから、1時間ほど緩やかにしてシンプルなビューを作成しました。参加者全員がDartを一度も使用していなかったとしても、すぐにプログラミングを開始することができました。彼らは言語ではなく反応的な意見を書くことに焦点を当てていました。Dartはよく働きました。

結局のところ、1人の参加者(特に作業進捗が良かった参加者)は言語について何も言及していないため、使用している言語が分かっているかどうかを尋ねました。彼らは知らなかった。言語は問題ではありませんでした。彼らは数分でDartでプログラミングしていました。

新しいシステムを学ぶことの難しい部分は、通常、言語を学ぶことではなく、良いコードを書くためのすべてのライブラリ、フレームワーク、ツール、パターン、ベストプラクティスなのです。その点、Dartライブラリとツールは非常に優れており、よく文書化されています。ある記事では、「おまけに、彼らはコードについて注意を払っており、今までに見たことないほどドキュメントが充実している」と述べています。ダートの学習は、時間を節約できるでしょう。

証拠として、Googleの大規模なプロジェクトでは、モバイルアプリをiOSに移植したいと考えていました。彼らはいくつかのiOSプログラマーを雇うつもりでしたが、代わりにFlutterを試してみることに決めた。彼らは、開発者がFlutterをスピードアップするのにどれくらい時間がかかったかを監視しました。彼らの結果は、プログラマーがDartとFlutterを学び、3週間で生産性を上げることができることを示しました。これは、プログラマーがAndroidだけでスピードアップすることを以前に観察していた5週間(これは、iOS向けに開発者を雇って訓練しなければならないということは言うまでもない)と比較しています。

最後に、「Why we chose Flutter and how it’s changed our company for the better.」という記事は、大企業のアプリケーションを3つのプラットフォーム(iOS、Android、およびWeb)すべてでDartに移行した会社からのものです:

Much easier to hire. We now look to take the best candidate regardless if they are from Web, iOS or Android.
We have 3x the bandwidth now that all of our teams are consolidated on a single code base.
Knowledge sharing is at an all time high
意訳:iOS,android,webのどの切り口からでも入れるし、コードが一つで済むのがありがたい。

DartとFlutterを使用して生産性を3倍になりました。彼らは以前に何をしていたのかを驚かすべきではありません。彼らは、多くの企業のように、別々の言語、ツール、プログラマーを利用して、各プラットフォーム(Web、iOS、Android)ごとに別々のアプリケーションを構築していました。Dartに切り替えると、3種類のプログラマーを雇う必要がなくなりました。また、既存のプログラマーをDartに移行するのは簡単でした。

彼は、プログラマーがFlutterを使い始めると、Dartと恋に落ちることが多いことを発見しました。彼らは言語的敏感さと儀式のなさ(??)(They like the terseness of the language, and the lack of ceremony. )が好きです。カスケード、名前付きパラメータ、非同期/待機、ストリームなどの言語機能が大好きです。とりわけ、Dartが可能にしたFlutter(ホットリロードなど)の機能とDartが構築する美しいパフォーマンスの高いアプリが大好きです。

Dart 2

この記事が公開される中、Dart 2がリリースされています。 Dart 2は、開発者の速度、開発者ツールの改善、型の安全性など、クライアントアプリケーションの構築経験を向上させることに重点を置いています。たとえば、Dart 2はサウンドタイプシステムと型推論を備えています。

ダーツ2はまた、新しいキーワードをオプショナルにします。これは引数をまったく使用せずに多くのFlutterビューを記述することが可能であることを意味し、可読性を向上させます。例えば:

optional_keyword.dart
Widget build(BuildContext context) =>
  Center(child:
    Column(children: [
      Text('Hello, World!'),
      Icon(Icons.star, color: Colors.green),
    ])
  )

また、Dart 2は型推論を使用してconstキーワードの多くの用途をオプショナルにしますが、const文の中でconstを重複して指定する必要はありません。たとえば、次の通りです:

NG_use_const*2.dart
const breakfast = {
   const Doughnuts(): const [const Cruller(), const BostonCream()], 
};
OK_use_const.dart
const breakfast = {
   Doughnuts(): [Cruller(), BostonCream()],
};

breakfastはconstなので、ほかの要素もconstであると推論します。

The secret is focus(秘密はフォーカス)

Dart2の改良点は、クライアント側の開発を最適化することに焦点を当てています。しかし、Dartは、サーバーサイド、デスクトップ、組み込みシステム、または他のプログラムを構築するための素晴らしい言語です。

フォーカスは良いことです。かなり多くの永続的な人気のある言語は、非常にフォーカスして利益を得ました。例えば:

  • Cは、オペレーティングシステムやコンパイラを書くためのシステムプログラミング言語でした。
  • Javaは組み込みシステム用に設計された言語でした。
  • JavaScriptは、Webブラウザ(!?)のスクリプト言語でした。
    • PHPは個人用HPの作成用(persol home page)として成功しました。(アメリカンジョーク?)

一方、多くの言語はPL / 1やAdaのような完全な汎用性を明示的に試してみました(そして失敗しました)。最も一般的な問題は、焦点がないと、これらの言語は没落したことです。

Dartを優れたクライアントサイド言語にする機能の多くは、サーバー側の使用言語としても優れています。たとえば、Dartがプリエンプティブなマルチタスキングを回避するという事実は、サーバ上のNodeと同じ利点をもたらしますが、はるかに型安全で優れています。

組み込みシステム用のソフトウェアを書くのと同じことが起こります。複数の同時入力を確実に処理するDartの能力はここで重要です。

最後に、Dartのクライアントでの成功は、JavaScriptとNodeの場合と同様に、サーバ上での使用には必然的に関心が高まります。クライアント/サーバーソフトウェアを構築するために人々が2つの異なる言語を使用するように強制するのはなぜでしょうか?

Conclusion(結論)

これはDartのエキサイティングな時間です。Dartを使用する人は好きで使用しています。Dart2の新機能は、あなたのツールの武器にさらに価値のある追加機能を提供します。 Dartを使用していない場合は、この記事でDartに関する新機能や相違点、価値ある情報、そしてFlutterを試してみてください。

88
63
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
88
63