DartとKotlinの違い

14139 ワード

Dart
ベースデータ型
Dartの主なタイプは以下のとおりです.
  • numの数値には2つのサブタイプがあります.
  • int:任意の長さの整数
  • double:デュアル精度浮動小数点数
  • String DartにおけるString付与値は、$を使用して値挿入を行うことができない点で、単一の二重引用符を使用することができます.このほか、三重引用符を使用して、複数行の文字列の割り当てを行うこともできます.(Kotlinと同様に、Kotlinには単一引用符がない唯一の違いです).String文字列では、Javaとは異なる\がデフォルトでエスケープ効果を有し、\のエスケープ作用を回避するには、文字列宣言の前にr、すなわちString s = r"
    "
    を加える必要がある.
  • bool bool値は対応する値であり、非bool値はfalse
  • である.
  • List
  • Map

  • 変数宣言
    言語
    変数#ヘンスウ#
    コンパイル時定数
    定数
    Dart
    具体的なタイプ、var
    const(変数)
    final(変数)
    Kotlin
    var
    const val
    val
    関数#カンスウ#
    Dartでは、関数もオブジェクトであり、戻り値が指定されていない場合はnull、すなわち を返す.
    関数宣言には、次の方法があります.
    //       
    String sayHello(String name){
        println("Hello, $name");
    }
    
    //     ,    :
    sayHello(name){
        println("Hello, $name");
    }//        ,               ,    
    
    //               ,        '=>' (Kotlin    '=')
    sayHello(name) => println("Hello, $name");
    
    //       ,       
    var sayHello = (name) => println("Hello, $name");
    
    

    関数の別名
    //         
    // typedef           (    )
    typedef void sayHello(String hellow)
    
    //                              
    // Kotlin    (    ) ->      
    

    オプションのパラメータ
    Dartは2つのオプションパラメータをサポートします.
  • 位置オプションパラメータ(廃棄済み)は[]を使用し、デフォルト値は:賦値、すなわち
    //   
    String sayHello(String name, [String greetings : 'Hello']) => println("$greetings, $name")
    
    //   
    sayHello('name', 'hello')
    
    を採用するが、この場合、位置オプションパラメータが多くなると、どのオブジェクトがどのオプションパラメータに対応するかを判別することは困難である.
  • ネーミングオプションパラメータは{}、デフォルト値は=、すなわち
    //   
    String sayHello(String name, {String greetings = 'Hello'}) => print("$greetings, $name")
    
    //   
    sayHello('name', greetings = 'hello')
    
  • を使用する.
    この2つのオプションパラメータ方式はPSを同時に使用することはできません:後者の言語として、Kotlinオプションパラメータの2つの方式はいずれもサポートされていますが、{}[]は必要ありません.
    オペレータとプロセス制御文
    DartのほとんどのコンテンツはC++、Javaと変わりません.次は前の2つとは異なるオペレータです.
    整頓オペレータ~/C++、Javaで整数演算子がないのは、整数を除いた場合のデフォルトの結果が整数であり、Dartでは実際の結果が返されるためです.
    int a = 3;
    int b = 2;
    print(a / b); // 1.5
    print(a ~/ b); // 1
    

    カスケード
    単一オブジェクトの一連の操作が必要な場合は、カスケードオペレータ..(Kotlinのapply拡張関数に対応)を使用します.
    class Person {
        String firstName;
        String lastName;
    }
    
    Person p = Person(); // new        
    p .. firstName = 'firstName'
      .. lastName = 'lastName';
    

    if ifは通常の用法と一致するが、bool以外の値を判断するとcheckモードで異常が放出され、productionモードではfalseと見なされる.
    ループ
    通常、forループは従来と一致し、反復オブジェクトがコンテナである場合、forEach((T) -> function)メソッドを使用して反復することができる.
    Swicth Case
    switchのパラメータはStringまたはnumであってもよい.文の内容が空であれば、breakを省略して空にする(次の文の内容を実行する)効果を達成することができる.空でなくても空になりたい場合は、手動でラベルを指定し、continueを使用してラベルを返す必要があります.
    switch(0){
        case 0:
        case 1:
            print('  ');
            break;
        case 2:
            print('    ');
            continue closed;
        case 3:
            print('x');
            break;
            closed:
        case 4:
            print('      ');
            break;
    }
    

    異常
    Dartでは、空でないオブジェクトを例外として放出できます.catchにタイプが指定されていない場合は、varのような任意のタイプの例外を処理できます.残りはJavaと似ています.
    クラスとオブジェクト
    DartはJavaと一致し、すべてのオブジェクトがクラスのインスタンスであり、すべてのクラスがObjectのサブクラスである(KotlinはAny).
    Dart 2では、newおよびconstのキーワードを省略してオブジェクトを作成できます.
    コンストラクション関数での値伝達および構築定数
    class Person {
        String firstName;
        String lastName;
    
        //    
        Person(this.firstName, String lastName){
            this.lastName = lastName;
        }
    
        // final           ,              
        //      
        Person(String a, String b) : firstName = a, lastName = b;
    
        //     
        const Person(this.firstName, this.lastName);
    
        //        
        Person.polar(this.lastName, this.firstName)
        Person(String firstName, String lastName) : this.polar(lastName, firstName)
    }
    

    コンストラクション関数実行プロセス:
    class Base {
        int a;
        int b;
    
        Base(this.a, int c) {
            b = c;
        }
    }
    
    class Ex : Base {
        int d;
    
        Ex(a, b , this.d) : super(a, b){
        }
    }
    

    プロセスは、Exオブジェクトが作成される->Ex初期化リストを呼び出す->Base初期化リストを呼び出す->Base構築方法の内容を呼び出す->Ex構築方法を呼び出す
    ファクトリコンストラクション関数:ファクトリコンストラクション関数はstatic静的変数と類似しており、thisポインタにアクセスできません.ファクトリコンストラクション関数はfactory接頭辞で始まり、初期化リストまたは初期化形式パラメータがない可能性があります.逆に、オブジェクトを返す関数体が必要です.
    class A {
        String name;
        static A cache;
    
        factory A(String name){
            if(cache == null){
                A.cache = new A.newObject(name);
            }
    
            return A.cache;
        }
    }
    

    Get Setメソッド
    クラスの各フィールドは暗黙的なGetterとSetterに対応し、呼び出しはKotlinと一致します.デフォルト呼び出しは、getおよびsetのキーワードを使用して拡張できます.フィールドがfinalまたはconstの場合、Getterメソッドのみが使用されます.
    class Person {
        String firstName;
        String lastName;
    
        // get   
        String get firstName => firstName + lastName;
    
        // set   
        set lastName => lastName = value
    }
    

    抽象クラス
    Dartではインタフェースとクラスが統一されており,クラスはインタフェースであり,Javaとabstractメソッドを用いて抽象クラスを定義し,抽象クラスはインスタンス化できない.
    いずれもインタフェースですが、継承と実装はJavaと似ています.継承キーワードはextends,実装キーワードはimplementsである.
  • 実装を使用すると、子クラスは親クラスのパラメータにアクセスできず、C++の純虚関数に似ていますが、複数のクラスの複数の関数を実装できます.
  • DartはJavaと一致し、単一継承方式を採用し、サブクラスは親非プライベート変数を継承することができる.

  • かき混ぜるMixinsは、異なるクラスでコード再利用を行うための方法である.Mixinsクラスを宣言するには、Objectから継承された構築メソッド(抽象クラス)のないクラスを作成する必要があります.
    abstract class MixinsExample {
        bool isSelected = false;
    
        void printCurrentState(){
            if(isSelected){
                print('Current state is selected');
            }else{
                print('Current state is unselected');
            }
        }
    }
    
    withキーワードで使用:
    class Content with MixinsExample{
        ...
    }
    

    StringBuffer
    文字列結合クラス:
    StringBuffer sb = new StringBuffer();
    
    sb.write("first");
    sb.writeAll(['array1', 'array2']);
    
    print(sb.toString());
    
    sb.clear();
    

    ようき
    Dartのコンテナは主にList,Set,Mapを含み,Javaの用法とほぼ一致する.
    List
    //   
    List count = new List();
    //       
    List from = [3, 2, 1];
    //       
    varfrom = [3, 2, 1];
    
    count.add(0);
    count.addAll(from);
    
    count.length; // 4
    count[0]; // 0
    
    //   ,      < 0     , = 0     , > 0     
    count.sort((a, b) => a - b); // [0, 1, 2, 3]
    
    count.remove(3); // 3
    count.indexOf(2); // 2
    count.removeAt(1); // 1
    count.removeWhere((i) => i == 0); // 0 
    count.clear(); // count.length   0
    

    Set
    Set set = new Set();
    
    set.addAll(['first', 'second', "third"]);
    
    set.length; // 3
    set.remove('second'); // true
    set.contains('third'); // true
    
    Set newSet = new Set.from(['third', 'forth']);
    
    //   
    Set intersection = set.inersection(newSet);
    //   
    intersection.isSubsetOf(set); // true
    

    Map
    Map> map = {
        'key1': ['array01', 'array02'],
        'key2': ['array11', 'array12']
    };
    //       
    var map = >{
        'key1': ['array01', 'array02'],
        'key2': ['array11', 'array12']
    };
    
    Map sMap = new Map();
    
    sMap['key'] = 'value';
    sMap.containsKey('key'); // true
    sMap.keys; // ['key']
    sMap.values; // ['value']
    sMap.remove('key'); // 'value'
    

    コンテナの反復
    List,MapはいずれもEfficientLengthIterableから継承されており反復可能であり,Set自身はforEach法を実現しているので,以上の3つの容器はいずれもforEach((T) => function)for(t in collection)で反復可能である.
    ライブラリのインポート
    インポートする唯一の必須パラメータは、指定したライブラリのURIです.内蔵ライブラリの場合、インポートには特別なURI:dart:schemeが必要です.他のライブラリでは、ファイルのシステムパスやpackage:schemeのようなフォーマットを使用できます.
    接頭辞
    2つのライブラリで競合する名前をインポートする場合は、接頭辞を追加することで区別できます.
    //             Element  
    import 'package:lib1/lib1.dart';
    import 'package:lib2/lib2.dart' as lib2;
    
    Element element1 = Element();
    Element element2 = lib2.Element();
    

    部分インポート
    import 'package:lib1/lib1.dart' show func;
    import 'package:lib2/lib2.dart' hide func;
    

    インポートの遅延
    次の場合、インポートを遅らせる必要がある場合があります.
  • 起動時間を短縮
  • A/Bテスト
  • は、使用する機能が少ない
  • をロードする.
    import 'package:greetings/hello.dart' deferred as greeting;
    
    Future greet() async{
        //             
        await gretting.loadLibrary();
        gretting.greet();
    }
    

    非同期
    Dartライブラリには、通常、I/O、ネットワークリクエストなどの時間のかかる操作を設定した後、メソッドの実行が完了するのを待つことなく、FutureオブジェクトとStreamオブジェクトを返す方法がたくさんあります.
    Future
    Futureを使用して完了した値を実行する必要がある場合は、次の2つの選択肢があります.
  • asyncawait asyncawaitは非同期であるが、コード的には同期動作のように見え、より理解しやすい:
    // await     async    
    Future checkVersion() async{
        //             await        ,       Future   
        //        await              
        var version = await lookUpVersion();
        ...
    }
    
  • FutureのAPIを使用してFutureのthen(function)を使用してFutureが完了した後に実行する必要があるコードを設定する:
    //      Future   
    HttpRequest.getString(url)
        .then((String result) {
            print(result);
        }).catchError(e){
            ...
        };
    
    then(function)メソッドも有効な非同期メソッドを順次実行する方法を提供する:
    //           Future        
    constlyQuery(url)
        .then((value) => expensiveWork(value))
        .then((_) => lengthyComputation())
        .then((_) => print('Done'))
        .catchError(e){
            ...
        };
    
    //       async   await    
    request() async {
        try{
            final value = await constlyQuery(url);
            await expensiveWork(value);
            await lengthyComputation();
            print('Done');
        }catch(e){
            ...
        }
    }
    
    //                 ,               
    Future delete() async => ...
    Future add()    async => ...
    Future select() async => ...
    
    doJobs() async {
        await Future.wait([
            delete(),
            add(),
            select()
        ]);
        print('Done');
    }
    
  • .
    Stream
    Streamから値を取得するには、次の2つのオプションがあります.
  • asyncと非同期ループ(await for)
    Future main() async {
        await for(varOfType identifier in expression){
            ...
        }
    }
    
    
    を使用する非同期ループの式には、次のようなStreamタイプが必要です.
  • ストリームが1つの値を読み出すのを待つ.
  • 値を循環本体内に入れて実行する.
  • ループは、Streamがオフになるまで1、2ステップを実行します.

  • リスニングを終了する必要がある場合、breakまたはreturnを使用して、ループを終了し、Streamのリスニングをキャンセルする.
  • Stream APIを使用してStreamクラスのlisten()メソッドを使用して、各ファイルまたはディレクトリを処理する関数を入力してファイルリストを購読する:
    void main(List arguments) {
        // ...
        FileSystemEntity.isDirectory(searchPath).then((isDir) {
          if (isDir) {
            final startingDir = Directory(searchPath);
            startingDir
                .list(
                    recursive: argResults[recursive],
                    followLinks: argResults[followLinks])
                .listen((entity) {
              if (entity is File) {
                searchFile(entity, searchTerms);
              }
            });
          } else {
            searchFile(File(searchPath), searchTerms);
          }
        });
    }
    
    //       async   await for    
    Future main(List arguments) async {
      // ...
        if (await FileSystemEntity.isDirectory(searchPath)) {
          final startingDir = Directory(searchPath);
          await for (var entity in startingDir.list(
              recursive: argResults[recursive],
              followLinks: argResults[followLinks])) {
            if (entity is File) {
              searchFile(entity, searchTerms);
            }
          }
        } else {
          searchFile(File(searchPath), searchTerms);
        }
    }
    
    //        
    Future readFileAwaitFor() async {
      var config = File('config.txt');
      Stream> inputStream = config.openRead();
    
      var lines = inputStream
          //       
          .transform(utf8.decoder)
          .transform(LineSplitter());
      try {
        await for (var line in lines) {
          print('Got ${line.length} characters from stream');
        }
        print('file is now closed');
      } catch (e) {
        print(e);
      }
    }
    
    
  • Generators
    一連の値の送信を遅延する必要がある場合は、generator functionを使用します.
  • 同期生成=>Iterableオブジェクトを返す:
    Iterable naturalsTo(int n) sync* {
        int k = 0;
        while(k < n)
            //    yield      
            yield k++;
    }
    
  • 非同期生成=>Streamオブジェクトを返します:
    Stream naturalsTo(int n) async* {
        int k = 0;
        while(k < n)
            //    yield      
            yield k++;
    }
    
  • ジェネレータが再帰的に呼び出された場合、yield*を使用して効率を向上させることができます:
    Iterable naturalsTo(int n) sync* {
        if(n > 0){
            yield n;
            yield* naturalsDownFrom(n - 1);
        }
    }
    
  • 呼び出し可能クラス
    クラスをメソッドのように呼び出す必要がある場合は、callメソッドを実装します.
    class FuctionLike{
        call(String a, String b, String c) => "$a, $b, $c"
    }
    
    main(){
        var fl = FunctionLike();
        var out = fl('a', 'b', 'c'); // 'a, b, c'
    }
    

    隔離区域
    マルチコアCPUの利点を十分に発揮するために、通常は共有メモリのスレッドを同時に実行するが、共有状態の同時実行はエラーが発生しやすく、コードの複雑化を招く可能性が高い.Dartコードは、他の分離領域から分離領域にアクセスしない状態を確保するために、各分離領域に独自のメモリスタックがあります.
    注釈
    //      
    class Todo {
        final String who;
        final String what;
    
        const Todo(this.who, this.what);
    }
    
    //   
    @Todo('name', 'job')
    void doSomething {
        print('do something');
    }