2013年にさかのぼると、ダートの公式1.0リリースは、ほとんどのGoogleサービスと同様にいくつかの報道を受けましたが、誰もがそれほど熱心だったわけではありません。 Googleの内部チームとして Dart言語でビジネスクリティカルなアプリを作成します。 5年後のDart2のよく考えられた再構築により、Googleは言語への取り組みを証明したようです。実際、今日では、開発者、特にJavaとC#のベテランの間で注目を集め続けています。
Dartプログラミング言語は、いくつかの理由で重要です。
大規模なエンタープライズシステムのC#またはJavaの世界の人々は、型の安全性、コンパイル時のエラー、およびリンターが重要である理由をすでに知っています。私たちの多くは、私たちが慣れているすべての構造、速度、正確さ、およびデバッグ可能性を失うことを恐れて、「スクリプト」言語を採用することを躊躇しています。
しかし、Dartの開発では、それをあきらめる必要はありません。モバイルアプリ、Webクライアント、バックエンドを同じ言語で記述でき、JavaとC#について今でも気に入っているものをすべて手に入れることができます。
そのために、C#またはJava開発者にとって新しいDart言語の主要な例をいくつか見ていきましょう。これらは、最後にDart言語のPDFにまとめられています。
注:この記事では、Dart2.xについてのみ説明します。バージョン1.xは「完全に調理」されていませんでした。特に、型システムは必須(C#やJavaなど)ではなくアドバイザリ(TypeScriptなど)でした。
まず、最も重要な違いの1つである、コードファイルの編成方法と参照方法について説明します。
C#では、クラスのコレクションがアセンブリにコンパイルされます。各クラスには名前空間があり、多くの場合、名前空間はファイルシステム内のソースコードの編成を反映していますが、最終的に、アセンブリはソースコードファイルの場所に関する情報を保持しません。
Javaでは、ソースファイルはパッケージの一部であり、名前空間は通常ファイルシステムの場所に準拠していますが、最終的には、パッケージは単なるクラスのコレクションです。
したがって、どちらの言語にも、ソースコードをファイルシステムからある程度独立させておく方法があります。
対照的に、Dart言語では、各ソースファイルは、他のソースファイルやサードパーティのパッケージを含め、参照するすべてのものをインポートする必要があります。同じ方法で名前空間はなく、ファイルシステムの場所からファイルを参照することがよくあります。変数と関数は、クラスだけでなく、トップレベルにすることができます。これらの点で、ダートはよりスクリプトに似ています。
したがって、考え方を「クラスのコレクション」から「含まれるコードファイルのシーケンス」のようなものに変更する必要があります。
Dartは、パッケージ編成とパッケージなしのアドホック編成の両方をサポートします。含まれるファイルのシーケンスを説明するために、パッケージのない例から始めましょう。
// file1.dart int alice = 1; // top level variable int barry() => 2; // top level function var student = Charlie(); // top level variable; Charlie is declared below but that's OK class Charlie { ... } // top level class // alice = 2; // top level statement not allowed // file2.dart import 'file1.dart'; // causes all of file1 to be in scope main() { print(alice); // 1 }
「プロジェクト」レベルがなく、スコープに他のソース要素を含める他の方法がないため、ソースファイルで参照するものはすべて、そのファイル内で宣言またはインポートする必要があります。
Dartでの名前空間の唯一の使用法は、インポートに名前を付けることです。これは、そのファイルからインポートされたコードを参照する方法に影響します。
// file2.dart import 'file1.dart' as wonderland; main() { print(wonderland.alice); // 1 }
上記の例では、パッケージなしでコードを整理しています。パッケージを使用するために、コードはより具体的な方法で編成されます。 apples
という名前のパッケージのパッケージレイアウトの例を次に示します。
apples/
pubspec.yaml
—パッケージ名、依存関係、およびその他のいくつかのものを定義しますlib/
apples.dart
—インポートとエクスポート。これは、パッケージのコンシューマーによってインポートされたファイルです。src/
seeds.dart
—他のすべてのコードはここにありますbin/
runapples.dart
—エントリポイントであるmain関数が含まれています(これが実行可能なパッケージであるか、実行可能なツールが含まれている場合)次に、個々のファイルではなく、パッケージ全体をインポートできます。
import 'package:apples';
重要なアプリケーションは、常にパッケージとして編成する必要があります。これにより、参照する各ファイルでファイルシステムパスを繰り返す必要が大幅に軽減されます。さらに、それらはより速く実行されます。また、パッケージを簡単に共有できます pub.dev 、他の開発者が自分で使用するために非常に簡単に取得できる場所。アプリで使用されるパッケージにより、ソースコードがファイルシステムにコピーされるため、必要に応じてこれらのパッケージを深くデバッグできます。
Cプラスプラスとは何ですか
ヌル、数値型、コレクション、動的型に関して、Dartの型システムには注意すべき大きな違いがあります。
C#またはJavaから来て、私たちは慣れています プリミティブ または 値 とは異なるタイプ 参照 または オブジェクト タイプ。実際には、値型はスタックまたはレジスタに割り当てられ、値のコピーが関数パラメータとして送信されます。代わりに、参照型がヒープに割り当てられ、オブジェクトへのポインターのみが関数パラメーターとして送信されます。値型は常にメモリを占有するため、値型変数をnullにすることはできず、すべての値型メンバーは初期化された値を持っている必要があります。
すべてがオブジェクトであるため、ダートはその区別を排除します。すべてのタイプは、最終的にタイプObject
から派生します。したがって、これは合法です。
int i = null;
実際、すべてのプリミティブは暗黙的にnull
に初期化されます。つまり、C#やJavaで慣れているように、整数のデフォルト値がゼロであると想定することはできず、nullチェックを追加する必要がある場合があります。
興味深いことに、Null
でもは型であり、単語null
Null
のインスタンスを参照します:
print(null.runtimeType); // prints Null
符号付きと符号なしのフレーバーを持つ8〜64ビットの整数型のよく知られた品揃えとは異なり、Dartの主な整数型は64ビット値のint
です。 (非常に大きな数の場合はBigInt
もあります。)
言語構文の一部としてバイト配列がないため、バイナリファイルの内容を整数のリストとして処理できます(例:List
)。
これがひどく非効率的であるに違いないとあなたが考えているなら、デザイナーはすでにそれを考えました。実際には、実行時に使用される実際の整数値に応じて、さまざまな内部表現があります。ランタイムは、int
にヒープメモリを割り当てません。それを最適化して、ボックス化されていないモードでCPUレジスタを使用できる場合はオブジェクト。また、ライブラリbyte_data
オファーUInt8List
およびその他の最適化された表現。
コレクションとジェネリックは、私たちが慣れているものとよく似ています。注意すべき主な点は、固定サイズの配列がないことです。List
を使用するだけです。配列を使用する場所ならどこでもデータ型。
また、3つのコレクションタイプを初期化するための構文サポートがあります。
final a = [1, 2, 3]; // inferred type is List, an array-like ordered collection final b = {1, 2, 3}; // inferred type is Set, an unordered collection final c = {'a': 1, 'b': 2}; // inferred type is Map, an unordered collection of name-value pairs
したがって、ダートを使用してくださいList
ここでは、Java配列、ArrayList
、またはVector
を使用します。またはC#配列またはList
。 Set
を使用するここで、Java / C#HashSet
を使用します。 Map
を使用するJavaを使用する場所HashMap
またはC#Dictionary
。
JavaScript、Ruby、Pythonなどの動的言語では、メンバーが存在しなくても参照できます。 JavaScriptの例を次に示します。
var person = {}; // create an empty object person.name = 'alice'; // add a member to the object if (person.age <21) { // refer to a property that is not in the object // ... }
これを実行すると、person.age
undefined
になりますが、とにかく実行されます。
同様に、JavaScriptで変数のタイプを変更できます。
var a = 1; // a is a number a = 'one'; // a is now a string
対照的に、Javaでは、コンパイラは型を知る必要があるため、上記のようなコードを記述できません。また、varキーワードを使用しても、すべての操作が有効であるかどうかがチェックされます。
var b = 1; // a is an int // b = 'one'; // not allowed in Java
Javaでは、静的型でのみコーディングできます。 (イントロスペクションを使用して動的な動作を行うことはできますが、構文の一部ではありません。)JavaScriptやその他の純粋に動的な言語では、動的型でのみコーディングできます。
Dart言語では、次の両方が可能です。
// dart dynamic a = 1; // a is an int - dynamic typing a = 'one'; // a is now a string a.foo(); // we can call a function on a dynamic object, to be resolved at run time var b = 1; // b is an int - static typing // b = 'one'; // not allowed in Dart
ダートには疑似タイプdynamic
がありますこれにより、すべてのタイプロジックが実行時に処理されます。 a.foo()
を呼び出そうとしました静的アナライザーを気にせず、コードは実行されますが、そのようなメソッドがないため、実行時に失敗します。
C#は元々Javaに似ていましたが、後で動的サポートが追加されたため、DartとC#はこの点でほぼ同じです。
Dartの関数構文は、C#やJavaよりも少し軽くて楽しいです。構文は次のいずれかです。
なぜ市場シェアが重要なのか
// functions as declarations return-type name (parameters) {body} return-type name (parameters) => expression; // function expressions (assignable to variables, etc.) (parameters) {body} (parameters) => expression
例えば:
void printFoo() { print('foo'); }; String embellish(String s) => s.toUpperCase() + '!!'; var printFoo = () { print('foo'); }; var embellish = (String s) => s.toUpperCase() + '!!';
int
のようなプリミティブを含め、すべてがオブジェクトであるためおよびString
、パラメーターの受け渡しは混乱を招く可能性があります。 ref
はありませんがC#のようにパラメーターを渡す場合、すべてが参照によって渡され、関数は呼び出し元の参照を変更できません。関数に渡されるときにオブジェクトは複製されないため、関数はオブジェクトのプロパティを変更する場合があります。ただし、intやStringなどのプリミティブの区別は、これらの型が不変であるため、事実上意味がありません。
var id = 1; var name = 'alice'; var client = Client(); void foo(int id, String name, Client client) { id = 2; // local var points to different int instance name = 'bob'; // local var points to different String instance client.State = 'AK'; // property of caller's object is changed } foo(id, name, client); // id == 1, name == 'alice', client.State == 'AK'
C#またはJavaの世界にいる場合は、次のような混乱を招くようにオーバーロードされたメソッドを使用している状況で呪われている可能性があります。
// java void foo(string arg1) {...} void foo(int arg1, string arg2) {...} void foo(string arg1, Client arg2) {...} // call site: foo(clientId, input3); // confusing! too easy to misread which overload it is calling
または、C#のオプションのパラメーターを使用すると、別の種類の混乱が発生します。
// c# void Foo(string arg1, int arg2 = 0) {...} void Foo(string arg1, int arg3 = 0, int arg2 = 0) {...} // call site: Foo('alice', 7); // legal but confusing! too easy to misread which overload it is calling and which parameter binds to argument 7 Foo('alice', arg2: 9); // better
C#では、呼び出しサイトでオプションの引数に名前を付ける必要がないため、オプションのパラメーターを使用してメソッドをリファクタリングすると危険な場合があります。リファクタリング後に一部の呼び出しサイトが合法である場合、コンパイラはそれらをキャッチしません。
ダートには、より安全で非常に柔軟な方法があります。まず第一に、オーバーロードされたメソッドは ない サポートされています。代わりに、オプションのパラメータを処理する2つの方法があります。
// positional optional parameters void foo(string arg1, [int arg2 = 0, int arg3 = 0]) {...} // call site for positional optional parameters foo('alice'); // legal foo('alice', 12); // legal foo('alice', 12, 13); // legal // named optional parameters void bar(string arg1, {int arg2 = 0, int arg3 = 0}) {...} bar('alice'); // legal bar('alice', arg3: 12); // legal bar('alice', arg3: 12, arg2: 13); // legal; sequence can vary and names are required
同じ関数宣言で両方のスタイルを使用することはできません。
async
キーワードの位置C#は、async
に対して紛らわしい立場にあります。キーワード:
Task Foo() {...} async Task Foo() {...}
これは、関数のシグネチャが非同期であることを意味しますが、実際には関数の実装のみが非同期です。上記の署名のいずれかが、このインターフェースの有効な実装になります。
interface ICanFoo { Task Foo(); }
Dart言語では、async
より論理的な場所にあり、実装が非同期であることを示します。
Future foo() async {...}
C#やJavaと同様に、Dartは字句スコープです。これは、ブロックで宣言された変数がブロックの最後でスコープ外になることを意味します。したがって、ダートはクロージャーを同じ方法で処理します。
Javaはプロパティのget / setパターンを普及させましたが、言語には特別な構文はありません。
// java private String clientName; public String getClientName() { return clientName; } public void setClientName(String value}{ clientName = value; }
C#には構文があります:
// c# private string clientName; public string ClientName { get { return clientName; } set { clientName = value; } }
Dartには、プロパティをサポートするわずかに異なる構文があります。
// dart string _clientName; string get ClientName => _clientName; string set ClientName(string s) { _clientName = s; }
Dartコンストラクターは、C#やJavaよりもかなり柔軟性があります。 1つの優れた機能は、同じクラス内の異なるコンストラクターに名前を付ける機能です。
class Point { Point(double x, double y) {...} // default ctor Point.asPolar(double angle, double r) {...} // named ctor }
クラス名だけでデフォルトのコンストラクターを呼び出すことができます:var c = Client();
コンストラクター本体が呼び出される前にインスタンスメンバーを初期化するための省略形は2種類あります。
class Client { String _code; String _name; Client(String this._name) // 'this' shorthand for assigning parameter to instance member : _code = _name.toUpper() { // special out-of-body place for initializing // body } }
コンストラクターは、スーパークラスコンストラクターを実行し、同じクラスの他のコンストラクターにリダイレクトできます。
Foo.constructor1(int x) : this(x); // redirect to the default ctor in same class; no body allowed Foo.constructor2(int x) : super.plain(x) {...} // call base class named ctor, then run this body Foo.constructor3(int x) : _b = x + 1 : super.plain(x) {...} // initialize _b, then call base class ctor, then run this body
JavaとC#の同じクラスで他のコンストラクターを呼び出すコンストラクターは、両方に実装があると混乱する可能性があります。 Dartでは、コンストラクターのリダイレクトに本体を含めることができないという制限により、プログラマーはコンストラクターのレイヤーをより明確にする必要があります。
factory
もあります関数をコンストラクターのように使用できるようにするキーワードですが、実装は単なる通常の関数です。これを使用して、キャッシュされたインスタンスまたは派生型のインスタンスを返すことができます。
class Shape { factory Shape(int nsides) { if (nsides == 4) return Square(); // etc. } } var s = Shape(4);
JavaとC#には、private
、protected
、public
などのアクセス修飾子があります。 Dartでは、これは大幅に簡略化されています。メンバー名がアンダースコアで始まる場合、パッケージ内のすべての場所(他のクラスを含む)に表示され、外部の呼び出し元からは非表示になります。そうでなければ、それはどこからでも見ることができます。 private
のようなキーワードはありません可視性を示します。
別の種類の修飾子は変更可能性を制御します:キーワードfinal
およびconst
その目的のためですが、それらは異なることを意味します:
var a = 1; // a is variable, and can be reassigned later final b = a + 1; // b is a runtime constant, and can only be assigned once const c = 3; // c is a compile-time constant // const d = a + 2; // not allowed because a+2 cannot be resolved at compile time
Dart言語は、インターフェース、クラス、および一種の多重継承をサポートします。ただし、interface
はありませんキーワード;代わりに、すべてのクラスもインターフェースであるため、abstract
を定義できます。クラスを作成して実装します。
abstract class HasDesk { bool isDeskMessy(); // no implementation here } class Employee implements HasDesk { bool isDeskMessy() { ...} // must be implemented here }
多重継承は、extends
を使用してメイン系統で行われます。キーワード、およびwith
を使用する他のクラスキーワード:
class Employee extends Person with Salaried implements HasDesk {...}
この宣言では、Employee
クラスはPerson
から派生しますおよびSalaried
、ただしPerson
はメインのスーパークラスであり、Salaried
ミックスイン(セカンダリスーパークラス)です。
私たちが慣れていない、楽しくて便利なDart演算子がいくつかあります。
カスケード 何にでもチェーンパターンを使用できるようにします。
emp ..name = 'Alice' ..supervisor = 'Zoltron' ..hire();
スプレッド演算子を使用すると、コレクションを初期化子でその要素のリストとして扱うことができます。
var smallList = [1, 2]; var bigList = [0, ...smallList, 3, 4]; // [0, 1, 2, 3, 4]
Dartにはスレッドがないため、JavaScriptにトランスパイルできます。代わりに、メモリを共有できないという意味で、個別のプロセスに似た「分離」があります。マルチスレッドプログラミングはエラーが発生しやすいため、この安全性はDartの利点の1つと見なされています。に 分離株間で通信する 、それらの間でデータをストリーミングする必要があります。受信したオブジェクトは、受信側の分離のメモリ空間にコピーされます。
C#またはJava開発者の場合、Dart言語は使い慣れているように設計されているため、すでに知っていることでDart言語をすばやく習得できます。そのために、私たちは ダートチートシートPDF 参考までに、特にC#およびJavaの同等のものとの重要な違いに焦点を当てます。
この記事に示されている違いと既存の知識を組み合わせると、ダートの最初の1日か2日で生産性を高めることができます。ハッピーコーディング!
関連: ハイブリッドパワー:フラッターの利点と利点Dartは、Googleによって開発された、最新の、タイプセーフで、簡単にアクセスできる言語です。ネイティブのデスクトップおよびモバイルプラットフォームにコンパイルされ、Webアプリ用のJavaScriptに変換されます。
マルチプラットフォームの汎用言語として、Dartは、Webおよびモバイルのフロントエンドとバックエンド、データベースアプリケーション、およびスクリプトに使用できます。 GoogleAdWordsのユーザーインターフェースはDartで構築されました。
セレンを使用してデータをスクレイピングする
Dartは、動的および静的型付け、非同期サポート、ラムダ関数など、C#、Java、Python、JavaScriptの優れた機能の多くを組み合わせた言語です。バグが発生しやすい複雑さを回避し、すばやく学習できるように注意深く設計されています。
練習用スクリプトは低い学習曲線ですばやく実行できるため、PythonとJavaScriptを最初に学習する言語として推奨されることがよくあります。ただし、ある言語のほとんどのスキルは他の言語に転用できるため、どの言語を最初にすることもできます。 C#から始めると、型の安全性が早期にわかるため、有益な場合があります。
Dartの構文は、最も近いいとこであるC#とよく似た外観と動作をします。また、Pythonと同様に、ソースコードからのスクリプトの解釈もサポートしています。
Dartは、事前コンパイル(AOT)またはジャストインタイム(JIT)のいずれかでコンパイルできます。 Dartアプリケーションをデプロイすると、ネイティブプラットフォームにコンパイルすることも、ソースコードから直接実行することもできます。
DartはオプションでJavaScriptに変換され、Dart(およびFlutter)アプリをブラウザーで実行できるようにします。また、ネイティブ実行可能ファイルへのコンパイルもサポートしています。