美文网首页Flutter小白教程系列
Flutter Dart语言快速入门

Flutter Dart语言快速入门

作者: 程序员指北 | 来源:发表于2020-01-07 11:27 被阅读0次

    转载请注明出处: https://learnandfish.com/

    入门简单的Dart程序

    // 定义一个函数
    printNumber(int number) {
      print('The number is $number.'); // 打印到控制台。
    }
    
    // 入口函数
    void main() {
      var number = 42; // 声明并初始化一个变量。
      printNumber(number); // 调用函数。
    }
    
    • // 代码注释。
    • $variableName (或 ${expression}) 获取变量值

    重要概念

    在学习 Dart 语言时, 应该基于以下事实和概念:

    • 万物皆对象, 无论是数字,函数和null都是对象。所有对象继承自Object类。
    • 尽管Dart语言是强类型的, 但是Dart可以推断类型, 上面的var number等价于int number。
    • 针对于不确定的数据类型,请使用dynamic。
    • Dart支持泛型, 如List<int>(整数列表)和List<dynamic>(任何类型的对象列表)。
    • 与Java不同, Dart中没有权限关键字"public", "protected", "private"。 如果标识符以下划线(_number)开头, 则认为是私有属性。
    • Dart语言定义的变量,如果不赋值,默认为空null。

    变量

    Dart内建数据类型如下:

    • Number 通过num声明
    • int 整数值
    • double 双精度浮点值
    void main() {
      var number = 1; // Dart会自动推断为int类型
      int value = 1; // 显示声明为int类型
      print(number == value); // 该值应为true, 因为上述两个变量的值和类型相同
    
      var pointNumber = 1.0; // Dart会自动推断为double类型
      double pointValue = 1.0; // 显示声明为double类型
      double pointValueCast = 1; // Dart2.1之后会自动转换为为double类型
      print(pointNumber == pointValue); // 该值应为true, 因为上述两个变量的值和类型相同
      print(pointNumber == pointValueCast); // 该值应为true, 因为上述两个变量的值和类型相同
    }
    
    • String
    • 以单引号或者双引号包裹。
    • 可以通过"+"连接。
    • 可以通过variableName或者{expression}获取取值。
    • 使用r前缀创建原始字符串。
    • 对象的常用方法请查阅String常用方法
    void main() {
      var s1 = "我是字符串1";
      String s2 = "我是字符串2";
      // s3虽然手动换行,但是输出的时候还是在一行
      var s3 = '我是'
          '字符串'
          '3';
      // s4和s5为多行字符串
      var s4 = """
       我是
       字符串
       4
       哈哈哈
      """;
      var s5 = '''
       我是
       字符串
       4
       哈哈哈
      ''';
      // s6会换行
      var s6 = "In a raw string, even \n isn't special.";
      // s7保持原样输出
      var s7 = r"In a raw string, even \n isn't special.";
      print(s1);
      print(s2);
      print(s3);
      print(s4);
      print(s5);
      print(s6);
      print(s7);
    }
    
    /* console
    我是字符串1
    我是字符串2
    我是字符串3
       我是
       字符串
       4
       哈哈哈
      
       我是
       字符串
       4
       哈哈哈
      
    In a raw string, even 
     isn't special.
    In a raw string, even \n isn't special.
    */
    
    • Boolean
    • Dart 使用 bool 类型表示布尔值。 Dart 只有字面量 true and false 是布尔类型, 这两个对象都是编译时常量。
    void main() {
      var b = true;
      var c = false;
      bool d; // 声明变量不赋值的情况下,默认为null
      bool e  = true;
      print(b);
      print(c);
      print(d);
      print(e);
    }
    /* console
    true
    false
    null
    true
     */
    
    • List
    • 几乎每种编程语言中最常见的集合可能是array或有序的对象集合。在Dart中的Array就是List对象, 通常称之为List。
    void main() {
      var list = [1, 2, 3];
      List list1 = [1, 2, 3];
      assert(list.length == 3);
      assert(list[1] == 2);
    
      list[1] = 1;
      assert(list[1] == 1);
    }
    
    • Set
    • 在Dart中Set是一个元素唯一且无序的集合。
    void main() {
      var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
      // Dart 推断 halogens 类型为 Set<String> 。如果尝试为它添加一个 错误类型的值,分析器或执行时会抛出错误。
      halogens.add('haha'); // 添加成功
    //  halogens.add(1); // 类型错误,编译时提示
     // 要创建一个空集,使用前面带有类型参数的 {} ,或者将 {} 赋值给 Set 类型的变量
      var names = <String>{};
      Set<String> names1 = {}; // 这样也是可以的。
    // var names = {}; // 这样会创建一个 Map ,而不是 Set 。
      var elements = <String>{};
      // 使用 add() 或 addAll() 为已有的 Set 添加元素
      elements.add('fluorine');
      elements.addAll(halogens);
      // 使用 .length 来获取 Set 中元素的个数
      assert(elements.length == 5);
    }
    
    • Map
    • Map是用来关联keys和values的对象。keys和values可以是任何类型的对象。
    • 在一个Map对象中一个key只能出现一次。但是value可以出现多次。
    void main() {
      var gifts = {
        // Key:    Value
        'first': 'partridge',
        'second': 'turtledoves',
        'fifth': 'golden rings'
      };
    
      var nobleGases = {
        2: 'helium',
        10: 'neon',
        18: 'argon',
      };
      // 以上 Map 对象也可以使用 Map 构造函数创建
      var gifts1 = Map();
      gifts['first'] = 'partridge';
      gifts['second'] = 'turtledoves';
      gifts['fifth'] = 'golden rings';
    
      var nobleGases2 = Map();
      nobleGases[2] = 'helium';
      nobleGases[10] = 'neon';
      nobleGases[18] = 'argon';
    
      // 赋值
      gifts['fourth'] = 'calling birds';
      // 从一个 Map 中获取一个 value
      var first = gifts['first'];
      // 获取Map的长度
      print(gifts.length);
    }
    
    • Rune和Symbol
    • 不常用,有兴趣可以自行学习。
    • 通过Symbol声明的变量, 通过#variableName调用

    final和const

    • 使用过程中从来不会被修改的变量, 可以使用final或const, 而不是var或者其他类型。
    • final变量的值只能被设置一次; const变量在编译时就已经固定(const变量是隐式final类型)。
    void main() {
      final name = 'Bob';
      final String nickname = 'Bobby';
    //  name = 'Jack'; // Error: 一个 final 变量只能被设置一次。
      // const是编译时就固定值
      const bar = 1000000; // 压力单位 (dynes/cm2)
      const double atm = 1.01325 * bar; // 标准气压
      // Const 关键字不仅可以用于声明常量变量。 还可以用来创建常量值。
      var foo = const []; // 等价于 var foo = [];
      final bar1 = const [];
      const baz = []; // Equivalent to `const []`
      // 非 Final , 非 const 的变量是可以被修改的,即使这些变量 曾经引用过 const 值。
      foo = [1, 2, 3]; // 曾经引用过 const [] 常量值。
      // final和const修饰的不能修改
    //  bar1 = [1]; // 编译时报错, final修饰的不可修改
    //  baz = [2]; // 编译时报错, const修饰的不可修改
    }
    

    函数

    • Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象, 并且有它的类型Function。
    • 这也意味着函数可以被赋值给变量或者作为参数传递给其他函数。也可以把Dart类的实例当做方法来调用。
    // 有返回值的函数
    bool showPrice() {
       return true;
    }
    
    // 返回值为void
    void printVoidNumber() {
      print('return void');
    }
    
    // 返回值为void, 此时void的可以省略
    printVoidNumber1() {
      print('return void');
    }
    
    // 如果一个函数函数体只有一行,可以用箭头代替大括号
    // => expr 语法是 { return expr; } 的简写。 => 符号 有时也被称为 箭头 语法。
    showBooleanValue() => true;
    
    // 将函数赋值给一个变量
    var a = showBooleanValue();
    
    
    void main() {
      print(a);
    }
    
    
    • 可选参数
    • 命名可选参数, 放在大括号内{}
        void enableFlags({bool bold, bool hidden}) {}
    
    • 位置可选参数, 放在中括号内[]
    String say(String from, String msg, [String device]) {
      var result = '$from says $msg';
      if (device != null) {
        result = '$result with a $device';
      }
      return result;
    }
    
    // 方法调用
    void main() {
      say('Bob', 'Howdy'); //不使用可选参数
      say('Bob', 'Howdy', 'smoke signal'); //使用可选参数
    }
    
    • 默认参数值
    /// 设置 [bold] 和 [hidden] 标志 ...
    void enableFlags({bool bold = false, bool hidden = false}) {}
    
    void main(){
      // bold 值为 true; hidden 值为 false.
      enableFlags(bold: true);
    }
    
    • 函数是一等公民
    • 一个函数可以作为另一个函数的参数。
    • 同样可以将一个函数赋值给一个变量。
    printElement(int element) => print(element);
    
    void mian(){
      var list = [1, 2, 3];
      
      // 将 printElement 函数作为参数传递。
      list.forEach(printElement);
    }
    
    • 匿名函数
    void main() {
      var list = ['apples', 'bananas', 'oranges'];
      list.forEach((item) {
        print('${list.indexOf(item)}: $item');
      });
    }
    
    • 闭包:其实闭包就是在一个函数中可以调用其他的函数,这样其他的函数可以使用本函数的参数及其他内容。

    运算符

    • 类型判断运算符
    • as 类型转换
    • is 判断是否为某类型
    • is! 判断不是某类型
    • 赋值运算符
    • a = value; 将value赋值给便里昂a
    • b ??= value; 如果b为空时, 将value赋值给b, 否则b的值保持不变。
    • 条件表达式
    • condition ? expr1 : expr2 如果条件为 true, 执行 expr1 (并返回它的值): 否则, 执行并返回 expr2 的值。
    • expr1 ?? expr2 如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。
    • 级联运算符
    • 可以实现对同一个对象进行一系列的操作。
    • 除了调用函数, 还可以访问同一对象上的字段属性。这通常可以节省创建临时变量的步骤, 同时编写出更流畅的代码。
    • 类似与build模式。
    class Person{
      int age;
      String name;
      
      Person({this.name, this.age});
      
      void say(String words) {
        print(name + words);
      }
    }
    void main(){
      Person() // 获取对象。
        ..name = 'Bob' // 调用成员变量。
        ..say('important');
      // 等价于下面的代码
      var person = Person(name: "Bob");
      person.say('important');
      // 级联运算符可以嵌套
      /*final addressBook = (AddressBookBuilder()
            ..name = 'jenny'
            ..email = 'jenny@example.com'
            ..phone = (PhoneNumberBuilder()
                  ..number = '415-555-0100'
                  ..label = 'home')
                .build())
          .build();*/
      // 在返回值为void的函数之后不能继续调用级联操作符
      var sb = StringBuffer();
      sb.write('foo') // write函数返回值是void, 不能再继续调用
        ..write('bar');  // 运行会报错
    }
    

    控制流程语句

    // if elseif else
    weatherStatus(){
      if (isRaining()) {
        you.bringRainCoat();
      } else if (isSnowing()) {
        you.wearJacket();
      } else {
        car.putTopDown();
      }
    }
    
    // for 循环
    text(){
      var message = StringBuffer('Dart is fun');
      for (var i = 0; i < 5; i++) {
        message.write('---$i!');
      }
      // for ... in ...
      var collection = [0, 1, 2];
      for (var x in collection) {
        print(x); // 0 1 2
      }
      // forEach
      collection.forEach((item) => print(item));
    }
    
    // while 和 do-while
    printSomethings() {
      while (!isDone()) {
        doSomething();
      }
      do {
        printLine();
      } while (!atEndOfPage());
    }
    
    // break 和 continue
    pauseSomethings(){
      while (true) {
        if (shutDownRequested()) break;
        processIncomingRequests();
      }
      // 执行yearsExperience大于等于5的元素
      for (int i = 0; i < candidates.length; i++) {
        var candidate = candidates[i];
        if (candidate.yearsExperience < 5) {
          continue;
        }
        candidate.interview();
      }
      // 如果candidate对象实现了Iterable接口, 可以调用如下方式
      candidates
          .where((c) => c.yearsExperience >= 5)
          .forEach((c) => c.interview());
    }
    
    // switch 和 case
    judgeType() {
      var command = 'OPEN';
      switch (command) {
        case 'CLOSED':
          executeClosed();
          break;
        case 'PENDING':
          executePending();
          break;
        case 'APPROVED':
          executeApproved();
          break;
        case 'DENIED': // 当command为该种情况时,由于该分支没有break语句会继续执行下一个分支,直到遇到break停止执行。
          executeDenied();
        case 'OPEN':
          executeOpen();
          break;
        default:
          executeUnknown();
      }
    }
    // assert 判断是否成立
    judgeEquals() {
      // 确认变量值不为空。
      assert(text != null);
      
      // 确认变量值小于100。
      assert(number < 100);
      
      // 确认 URL 是否是 https 类型。
      assert(urlString.startsWith('https'));
      // assert 的第二个参数可以为其添加一个字符串消息。
      assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
    }
    

    异常处理

    • Dart 代码可以抛出和捕获异常。
    • 异常表示一些未知的错误情况。如果异常没有被捕获, 则异常会抛出, 导致抛出异常的代码终止执行。
    • throw 可以抛出Dart定义的异常, 也可以抛出任意对象
    // 高质量的生产环境代码通常会实现 Error 或 Exception 类型的异常抛出。
    throw FormatException('Expected at least 1 section');
    throw 'Out of llamas!';
    // 完整的try catch finally代码
    try {
      // 代码块
    } on Exception catch (e) {
      // 捕获到异常走这里
    } finally {
      // 无论是否捕获异常, 最终都会走这里
    }
    

    类和构造函数

    • 通过class关键字声明。
    • 在没有声明构造函数的情况下, Dart会提供一个默认的构造函数。默认构造函数没有参数并会调用父类的无参构造函数。
    class Point {
      num x, y;
    
      // 构造函数的第一种方法
      Point(num x, num y) {
        // 还有更好的方式来实现下面代码,敬请关注。
        this.x = x;
        this.y = y;
      }
      
      // 构造函数的第二种方法
      Point(this.x, this.y)
      
      // 构造函数的第三种方法--命名构造函数
      Point.origin(){
        x = 0;
        y = 0;
      }
    }
    
    • 类的继承
    • 子类通过关键字extends继承父类。
    • 默认情况下, 子类的构造函数会自动调用父类的默认构造函数(匿名, 无参数)。
    • 如果父类没有匿名无参的构造函数, 则在子类中需要手动调用父类的构造函数。
    class Person {
      String firstName;
      
      Person.fromJson(Map data){
        print("I'm $firstName");
      }
    }
    
    class Employee extends Person {
      
      Employee.fromJson(Map data) : super.fromJson(data){
        print("I'm Employee");
      }
      
    }
    
    main() {
      var emp = new Employee.fromJson({});
    
      if (emp is Person) {
        // Type check
        emp.firstName = 'Bob';
      }
      (emp as Person).firstName = 'Bob';
    }
    
    • 构造函数不仅可以调用父类构造函数, 还可以在构造函数体执行之前初始化成员变量。
    import 'dart:math';
    
    class Point {
      final num x;
      final num y;
      final num distance;
    
      Point(x, y)
          : x = x,
            y = y,
            distance = sqrt(x * x + y * y);
    }
    
    • 重定向构造函数
    class Point {
      num x, y;
    
      // 类的主构造函数。
      Point(this.x, this.y);
    
      // 指向主构造函数
      Point.alongXAxis(num x) : this(x, 0);
    }
    
    • 常量构造函数
    • 如果该类生成的对象是固定不变的, 那么就可以把这些对象定义为编译时常量。
    • 为此需要定义一个const构造函数, 并且声明所有实例变量为final。
    class ImmutablePoint {
      static final ImmutablePoint instance =
          const ImmutablePoint(0, 0);
    
      final num x, y;
    
      const ImmutablePoint(this.x, this.y);
    }
    
    • 工厂构造函数
    • 当执行构造函数并不总是创建这个类的一个新实例时, 则使用 factory 关键字。
    • 一个工厂构造函数可能返回一个cache中的实例。
    class Logger {
      final String name;
      bool mute = false;
    
      // 从命名的 _ 可以知,
      // _cache 是私有属性。
      static final Map<String, Logger> _cache =
          <String, Logger>{};
    
      factory Logger(String name) {
        if (_cache.containsKey(name)) {
          return _cache[name];
        } else {
          final logger = Logger._internal(name);
          _cache[name] = logger;
          return logger;
        }
      }
    
      // 私有命名构造函数 
      Logger._internal(this.name);
    
      void log(String msg) {
        if (!mute) print(msg);
      }
    }
    
    • Getter 和 Setter方法
    class Person {
      num age;
      final String name;
      final String hobby;
      
      // Getter
      String get hobby => "basketball";
      // Setter
      set hobby(String hobbyName) => hobby = hobbyName;
      
      Person(this.name, this.age)
    }
    
    • abstract 和 implements
    • abstract抽象类, 类中的抽象方法通过分号结束, 不用实现函数体, 故可以省略大括号。
    • implements实现接口。每个类都隐式的定义了一个接口, 接口包含该类所有的成员及其实现的接口。
    // 抽象类
    abstract class Person {
        void walk(); // 抽象方法
    }
    
    class Animal { 
      void fly() => print("I can fly");
    }
    
    class Bird implements Animal {
      void fly() {
        // 具体实现
      }
    }
    
    • 重写运算符 通过operator重写
    class Vector {
      final int x, y;
    
      Vector(this.x, this.y);
      
      // 返回值 operator 运算符(参数) {具体实现}
      Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
      Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
    
    }
    
    • noSuchMethod()
    • 当代码尝试调用类中不存在的方法时, 会抛出NoSuchMethodError异常, 可以通过重写该方法实现自己想要的结果。
    class Animal {
      
      @override
      void noSuchMethod(Invocation invocation){
        // 具体实现
      }
    }
    
    • 枚举类型
    enum Color {
      RED, GREEN, BLUE
    }
    
    • Mixin为类添加新功能
    • Mixin是复用类代码的一种途径, 复用的类可以不存在继承关系。
    • 通过with后面跟一个或者多个类进行复用。
    • 通过mixin定义一个Mixin类, Mixin类通过on复用其他类
    class Musician extends Performer with Musical {
      // ···
    }
    
    class Maestro extends Person
        with Musical, Aggressive, Demented {
      Maestro(String maestroName) {
        name = maestroName;
        canConduct = true;
      }
    }
    
    mixin MusicalPerformer on Musician {}
    
    • 静态变量和静态类型
    class Animal {
      
      static const height = 180;
      
      static num distance(){
        return 100;
      }
      
    }
    

    // 通过import导入
    import 'dart:html';
    // 通过as指定别名, 调用时通过lib2调用
    import 'package:lib2/lib2.dart' as lib2;
    // 导入库的一部分, 减少包体积
    // Import only foo.
    import 'package:lib1/lib1.dart' show foo;
    
    // Import all names EXCEPT foo.
    import 'package:lib2/lib2.dart' hide foo;
    // 延迟加载库, 当使用时进行加载
    import 'package:greetings/hello.dart' deferred as hello;
    
    Future greet() async {
      // 使用时使用loadLibrary()加载
      await hello.loadLibrary();
         hello.printGreeting();
       }
    

    异步(Future和Stream)

    • Future 使用async 和 await 构造。
    Future<bool> downLoad(String url) async {
      val result = await down();
      return result;
    }
    
    • Stream能够多次响应事件, 比如下载进度回调常用。
    • 有个博客介绍的比较详细, 请查看Future使用Stream介绍

    typedefs

    • 为函数定义别名
    typedefs Compare<T> = int Function(T a, T b);
    

    注释

    // 单行注释
    
    /*
    多行注释
    多行注释
    多行注释
     */
    
    /// 文档注释
    /// 文档注释
    
    /**
    * 文档注释
    */
    

    如果你觉得本篇博客对你有用,可以点个赞,评个论或者打个赏给博主增加动力哦。

    相关文章

      网友评论

        本文标题:Flutter Dart语言快速入门

        本文链接:https://www.haomeiwen.com/subject/dodractx.html