Dart Way 1

缘起

  • Dart 可以同时在 Mobile/Web/Server 三端跑,很像 nodejs,不过没有 nodejs 那么好命

  • 需要一个可以打通 Mobile、Web 的 tk,又不想用 RN的,可以跟着了解一下

目的

  • 记录使用过程

    • 安装/配置
      $ brew tap dart-lang/dart
      $ brew install dart
      # 刚发布的复活版 Dart 2.1
      $ brew info dart
      $ dart --version
      Dart VM version: 2.1.0 (Tue Nov 13 18:22:02 2018 +0100) on "macos_x64"
      # Dart 的工具包管理工具叫 pub (Flutter 有自己的一套工具管理包):
      $ pub --version
      Pub 2.1.0
      # 编辑器选用 VS Code,所以把官方的 [Dart 插件](https://marketplace.visualstudio.com/items?itemName=Dart-Code.dart-code)装一下
      复制代码
  • 个人比较喜欢 terminal 风格,所以先从 Server 端开始,首先当然是 hello world,除了第三行 print 的参数之外,简直跟 C 一模一样:

    void main() {
      for (int i = 0; i < 5; i++) {
        print('hello ${i + 1}');
      }
    }
    复制代码

    可以直接在 vscode(也可以是 DartPad,如果你能忍的话) 点击 run 运行,当然可以可以直接字符界面下来:

    $ dart --enable-asserts test.dart
    hello 1
    hello 2
    hello 3
    hello 4
    hello 5
    复制代码
  • 如果只是简单看下代码,估计了解一下 Sample 这一页就够了:

    1. 变量定义:
    // 把 var 去掉直接就是 Python ...
    var name = 'Voyager I';
    var year = 1977;
    var antennaDiameter = 3.7;
    var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
    var image = {
      'tags': ['saturn'],
      'url': '//path/to/saturn.jpg'
    };
    复制代码

    更多变量定义细节在这里

    1. 控制流:
    if (year >= 2001) {
      print('21st century');
    } else if (year >= 1901) {
      print('20th century');
    }
    
    for (var object in flybyObjects) {
      print(object);
    }
    
    for (int month = 1; month <= 12; month++) {
      print(month);
    }
    
    while (year < 2016) {
      year += 1;
    }
    复制代码

    更多控制流细节在这里

    1. 函数定义:
    int fibonacci(int n) {
      if (n == 0 || n == 1) return n;
      return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    var result = fibonacci(20);
    复制代码

    官方建议每个函数的参数和返回值都显示定义,更适合大型应用协作。

    关于函数的一个语法糖是,可以用 => 定义匿名函数(确实有点儿像 PHP),比如下面这个定义了一个简单匿名函数用作 where()函数的参数,过滤 name 中包含 turn 的元素,遍历并针对每个符合条件的元素调用 print

        flybyObjects.where((name) => name.contains('turn')).forEach(print);
    复制代码

    关于函数定义的更多细节在这里

    1. 注释跟 C 语言一样,行注释用 //,段注释用 /* 我是注释 */, 更高级的用法,比如 doc-testing 之类的细节在这里

    2. 包管理也是选了 import 关键字,比如调用内置的 libs:

    // Importing core libraries
    import 'dart:math';
    
    // Importing libraries from external packages
    import 'package:test/test.dart';
    
    // Importing files
    import 'path/to/my_other_file.dart';
    复制代码
      • 这里有一个类,包含 1 个方法;2 个构造函数;3 个属性;其中的 launchYear 属性展示了如何在 Dart 中配合 getter 函数定义一个只读属性:
      class Spacecraft {
        String name;
        DateTime launchDate;
      
        // Constructor, with syntactic sugar for assignment to members.
        Spacecraft(this.name, this.launchDate) {
          // Initialization code goes here.
        }
      
        // Named constructor that forwards to the default one.
        Spacecraft.unlaunched(String name) : this(name, null);
      
        int get launchYear =>
            launchDate?.year; // read-only non-final property
      
        // Method.
        void describe() {
          print('Spacecraft: $name');
          if (launchDate != null) {
            int years =
                DateTime.now().difference(launchDate).inDays ~/
                    365;
            print('Launched: $launchYear ($years years ago)');
          } else {
            print('Unlaunched');
          }
        }
      }
      复制代码

      Spacecraft 类的用法如下:

      var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
      voyager.describe();
      var voyager3 = Spacecraft.unlaunched('Voyager III');
      voyager3.describe();
      复制代码

      关于类的高级内容在这里

    1. 继承

      • Dart 走的是要聚合不要多继承的单继承设计思路
      • 下面 mixin 部分有更详细介绍,这里先看一眼一个简单的例子:
      class Orbiter extends Spacecraft {
        num altitude;
        Orbiter(String name, DateTime launchDate, this.altitude)
            : super(name, launchDate);
      }
      复制代码
      • 老规矩,关于 Dart 的继承详情在这里
    2. Mixin

      • 上面提到要聚合不要多继承,基本已经被大多数现代变成语言接受,至于 mixin 这个概念基本不用介绍了吧,好像也没有看到那种语言里面有个比较贴切的翻译,还不如直接就用 mixin.
      • 上例子:
      class Piloted {
        int astronauts = 1;
        void describeCrew() {
          print('Number of astronauts: $astronauts');
            }
      }
      复制代码

      Piloted 这个类就可以作为一个 mixin 来用,比如这样,用 extends ... with 关键字实现:

      class PilotedCraft extends Spacecraft with Piloted {
        // ···
      }
      复制代码

      这样 PilotedCraft 类就不仅有继承自 Spacecraft 的方法和属性,也有了来自 Pilotedastronauts 属性和 describeCrew 方法。 mixin 本身就我的理解来讲,更倾向于把不包含数据的单纯算法进行包装,脱离了数据的纯算法,方便代码复用。

    3. 接口和抽象类

      • Dart 没有接口的概念,取而代之的是每个类默认的就可以用作一个接口,所以可以直接 实现 任何一个类:
      class MockSpaceship implements Spacecraft {
        // ···
      }
      复制代码
      • 关于显示的使用接口,在这里有详细介绍
      • 抽象类是被支持的,抽象类里面当然包含抽象方法(函数体都是空的那种):
      abstract class Describable {
        void describe();
      
        void describeWithEmphasis() {
          print('=========');
          describe();
          print('=========');
        }
      }
      复制代码

      所有 extendsDescribale 的类都默认拥有 describeWithEmphasis 方法,该方法自动调用最终实例化对象自己定义的 describe 方法(逻辑如上)。

    4. Async 异步

      • async/await 这两年好像在语言设计界比较吃香,比如 Python 3.x 里面也用这俩词代表的异步思路解决 callback 嵌套调用带来的麻烦和多任务场景的任务。其他语言,比如 Obj-C 就不,人家用的是 block,嗯嗯高大上的样子... 上例子:
      const oneSecond = Duration(seconds: 1);
      // ···
      Future<void> printWithDelay(String message) async {
        await Future.delayed(oneSecond);
        print(message);
      }
      复制代码

      上面这段翻译成非 async/await 的写法就是这样(不明白 _Future之类的 是什么意思没关系,猜一下,基本也是你猜的那个意思:)):

      Future<void> printWithDelay(String message) {
        return Future.delayed(oneSecond).then((_) {
          print(message);
        });
      }
      复制代码

      再来一个例子说明 async/await 是如何简化异步逻辑,带来更好的代码可读性的:

      Future<void> createDescriptions(Iterable<String> objects) async {
        for (var object in objects) {
          try {
            var file = File('$object.txt');
            if (await file.exists()) {
              var modified = await file.lastModified();
              print(
                  'File for $object already exists. It was modified on $modified.');
              continue;
            }
            await file.create();
            await file.writeAsString('Start describing $object in this file.');
          } on IOException catch (e) {
            print('Cannot create description for $object: $e');
          }
        }
      }
      复制代码

      针对 streams 类的任务场景,Dart 提供了 async* 来进一步提高代码的可阅读性:

      Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
        for (var object in objects) {
          await Future.delayed(oneSecond);
          yield '${craft.name} flies by $object';
        }
      复制代码

      关于 Future/Stream 等等 Dart 里面的关键字意思,以及 Dart 是如何解决异步任务场景的思路,详情在这里

    5. 异常处理

      • 基本没什么好说的,用 throw 抛异常:
      if (astronauts == 0) {
        throw StateError('No astronauts.');
      }
      复制代码
      • 异常捕捉是通过 try... on/catch... finally 这种,上例子:
      try {
        for (var object in flybyObjects) {
          var description = await File('$object.txt').readAsString();
          print(description);
        }
      } on IOException catch (e) {
        print('Could not describe object: $e');
      } finally {
        flybyObjects.clear();
      }
      复制代码
      • 有一个需要注意的点是,Dart 的异常捕捉是无论异步、同步环境下都生效的,所以,基本上你怎么想的,程序就会怎么跑,不用人去适应机器,大赞。
      • Dart 在异常处理上还有些小心思、小设计的,比如 rethrow 和 stack traces 细节等,详情在这里
    6. 本文基本是官方 Sample 的翻译,看不懂基本就是翻译的太水,直接去看原文就好 :)

转载于:https://juejin.im/post/5c0b2ba851882542075d3bb2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值