【Flutter入门到进阶】Dart基础篇---基于对比Java学习Dart

16 篇文章 10 订阅
6 篇文章 1 订阅

1 Dart语言特性

1.1 简介

1.1.1 说明

        2011年10月,在丹麦召开的 GOTO 大会上,Google 发布了一种新的编程语言 Dart 。如同 Kotlin 和 Swift 的出现,分别是为了解决 Java 和 Objective-C 在编写应用程序的一些实际问题一样,Dart 的诞生正是要解决 JavaScript 存在的、在语言本质上无法改进的缺陷。

那么,JavaScript 到底有哪些问题和缺陷呢? JavaScript 之父布兰登 · 艾克(Brendan Eich)曾在一次采访中说,JavaScript“几天就设计出来了”。

概括来说,他对JavaScript的设计思路是这样的:

        - 借鉴C语言的基本语法;

        - 借鉴 Java 语言的数据类型和内存管理机制;

        - 借鉴 Scheme 语言,将函数提升到“第一等公民”(first class)的地位;

        - 借鉴 Self 语言,使用基于原型(prototype)的继承机制。

所以,JavaScript 实际上是两类编程语言风格的混合产物:(简化的)函数式编程风格,与(简化的)面向对象编程风格。

由于设计时间太短,一些细节考虑得不够严谨,导致后来很长一段时间,使用 JavaScript 开发的程序混乱不堪。出于对 JavaScript 的不满,Google 的程序员们决定自己写一个新语言来换掉它,所以 Dart 的最初定位也是一种运行在浏览器中的脚本语言。

而为了推广 Dart,Google 甚至将自己的 Chrome 浏览器内置了 Dart VM,可以直接高效地运行 Dart 代码。而对于普通浏览器来说,Google 也提供了一套能够将 Dart 代码编译成JavaScript 代码的转换工具。这样一来,开发者们就可以毫无顾虑地使用 Dart 去开发了,而不必担心兼容问题。再加上出身名门,Dart 在一开始就赢得了部分前端开发者的关注。

但,JavaScript 的生命力似乎比预想的更强大。

原本 JavaScript 只能在浏览器中运行,但 Node.js 的出现让它开始有能力运行在服务端,很快手机应用与桌面应用也成为了 JavaScript 的宿主容器,一些明星项目比如 React、React Native、Vue、Electron、NW(node-webkit)等框架如雨后春笋般崛起,迅速扩展了它的边界。

于是,JavaScript 成为了前后端通吃的全栈语言,前端的开发模式也因此而改变,进入了一个新的世界。就如同 Atwood 定律描述的:凡是能用 JavaScript 写出来的系统,最终都会用 JavaScript 写出来(Any application that can be written in JavaScript, will eventually be written in JavaScript.)。

JavaScript 因为 Node.js 焕发了第二春,而 Dart 就没有那么好的运气了。由于缺少顶级项目的使用,Dart 始终不温不火。2015年,在听取了大量开发者的反馈后,Google 决定将内置的 Dart VM 引擎从 Chrome 移除,这对 Dart 的发展来说是重大挫折,替代 JavaScript 就更无从谈起了。

但,Dart 也借此机会开始转型:在 Google 内部孵化了移动开发框架 Flutter,弯道超车进入了移动开发的领域;而在 Google 未来的操作系统 Fuchsia 中, Dart 更是被指定为官方的开发语言。

与此同时,Dart 的老本行,浏览器前端的发展也并未停滞。著名的前端框架 Angular,除了常见的 TS 版本外,也在持续迭代对应的 Dart 版本[AngularDart](https://github.com/dart-lang/angular)。(不过不得不说的是,这个项目的star一直以来只有可怜的1,100出头)。

也正是因为使用者不多、历史包袱少,所以在经历了这么多的故事后,Dart可以彻底转变思路,成为专注大前端与跨平台生态的语言。

1.1.2 官方文档

https://dart.cn/samples

1.1.3 安装

https://baijiahao.baidu.com/s?id=1683896164474193937&wfr=spider&for=pc

https://blog.csdn.net/weixin_45304503/article/details/127012751

1.2 特性

1.2.2 JIT 与 AOT

        借助于先进的工具链和编译器,Dart 是少数同时支持 JIT(Just In Time,即时编译)和 AOT(Ahead of Time,运行前编译)的语言之一。那,到底什么是 JIT 和 AOT 呢?语言在运行之前通常都需要编译,JIT 和 AOT 则是最常见的两种编译模式。

        - JIT 在运行时即时编译,在开发周期中使用,可以动态下发和执行代码,开发测试效率高,但运行速度和执行性能则会因为运行时即时编译受到影响。

        - AOT 即提前编译,可以生成被直接执行的二进制代码,运行速度快、执行性能表现好,但每次执行前都需要提前编译,开发测试效率低。

        总结来讲,在开发期使用 JIT 编译,可以缩短产品的开发周期。Flutter 最受欢迎的功能之一热重载,正是基于此特性。而在发布期使用 AOT,就不需要像 React Native 那样在跨平台 JavaScript 代码和原生 Android、iOS 代码之间建立低效的方法调用映射关系。所以说, Dart 具有运行速度快、执行性能好的特点。

        那么,如何区分一门语言究竟是 AOT 还是 JIT 呢?通常来说,看代码在执行前是否需要编译即可。如果需要编译,通常属于 AOT;如果不需要,则属于 JIT。AOT 的典型代表是 C/C++,它们必须在执行前编译成机器码;而 JIT 的代表,则包括了如 JavaScript、Python 等几乎所有的脚本语言。

1.2.2 内存分配与垃圾回收

        Dart VM 的内存分配策略比较简单,创建对象时只需要在堆上移动指针,内存增长始终是线性的,省去了查找可用内存的过程。

        在 Dart中,并发是通过 Isolate 实现的。Isolate 是类似于线程但不共享内存,独立运行的 worker 。这样的机制,就可以让 Dart 实现无锁的快速分配。

        Dart 的垃圾回收,则是采用了多生代算法。新生代在回收内存时采用“半空间”机制,触发垃圾回收时,Dart 会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存。回收过程中,Dart 只需要操作少量的“活跃”对象,没有引用的大量“死亡”对象则被忽略,这样的回收机制很适合 Flutter 框架中大量 Widget 销毁重建的场景。

1.2.3 单线程模型

        支持并发执行线程的高级语言(比如,C++、Java、Objective-C),大都以抢占式的方式切换线程,即:每个线程都会被分配一个固定的时间片来执行,超过了时间片后线程上下文将被抢占后切换。如果这时正在更新线程间的共享资源,抢占后就可能导致数据不同步的问题。

        解决这一问题的典型方法是,使用锁来保护共享资源,但锁本身又可能会带来性能损耗,甚至出现死锁等更严重的问题。

        这时,Dart 是单线程模型的优势就体现出来了,因为它天然不存在资源竞争和状态同步的问题。这就意味着,一旦某个函数开始执行,就将执行到这个函数结束,而不会被其他 Dart 代码打断。

        所以,Dart 中并没有线程,只有 Isolate (隔离区)。Isolates 之间不会共享内存,就像几个运行在不同进程中的 worker,通过事件循环(Event Looper)在事件队列(Event Queue)上传递消息通信。

1.3 指令

1.3.1 dart 命令支持如下的常用选项:

--enable-asserts - 开启断言

--version - 查看 Dart VM 版本

1.3.2 另外它还支持 Observatory 选项,用于分析和调试 Dart 程序。常用选项包括:

--enable-vm-service - 在本地 8181 端口开启 Observatory 服务

--observe - 相当于同时指定 --enable-vm-service 和 --pause-isolates-on-exit

1.3.3 Dart 语言本身还在快速演化中。所以要注意以下变化:

        1、在 Dart 2.6 以及之前版本,dart2aot 用于生成 AOT 镜像

        2、 Dart 2.6 之后,dart2native 命令取代了 dart2aot (前者是后者的超集)。

        3、dart2native

        dart2native bin/main.dart -o bin/my_app

        4、另一种是 AOT snapshot,它不包含 Dart 运行时,所以需要使用 dartaotruntime 来运行。

        5、dartaotruntime

        dart2native bin/main.dart -k aot

        dartaotruntime bin/main.aot

1.3.4 但是注意,在后续版本中对应命令也进行了调整

# 编译命令的格式如下: 
# dart compile <subcommand> [arguments]

$ dart compile --help
Compile Dart to various formats.

Usage: dart compile <subcommand> [arguments]
-h, --help    Print this usage information.

Available subcommands:
  aot-snapshot                Compile Dart to an AOT snapshot.
  exe                         Compile Dart to a self-contained executable.
  jit-snapshot                Compile Dart to a JIT snapshot.
  js                          Compile Dart to JavaScript.
  kernel                      Compile Dart to a kernel snapshot.

Run "dart help" to see global options.


# 编译成可执行文件: 
$ dart compile exe hello.dart   # 将hello.dart源文件编译成可执行文件
                                # 默认输出的文件名与源文件同名, 后缀为.exe
                                # 上面这条命令生成 hello.exe 文件, 
                                # 虽然在macOS中生成的文件名是hello.exe, 但是并不影响运行
                                # "./hello.exe" 运行可执行程序

2 运行区别

2.1 运行方式

2.1.1 java

运行步骤
javac
java

2.1.2 C

2.1.3 dart

运行步骤
dart demo.dart

3 变量 

3.1 变量

3.1.1 命名

在Dart语言当中,定义变量的方式是

dataType viriableName = Initial Valute

这里其实和Java是一样的,不仅如此连命名的方式也和Java相同,都是采用驼峰命名的方式。

3.1.2 声明

在声明的时候,除了基本数据类型之外,还有三种变量的声明: var,dynamic,Object

        var:如果没有初始值的时候,var可以变成任意类型,如果有初始值,那么类型会被锁定。

        dynamic:动态任意类型,编译阶段不检查类型。

        Object: 动态任意类型,在编译阶段检查类型。

代码示例

void main(){
  // a 的数据类型可以随意改变,这种类型就是 dynamic
  var a ;
  a = 10;
  a = "dart";

  // 这里我们使用 dynamic 声明
  dynamic d = 10;
  d = 'dart';
}

3.1.3 默认值

        1.没有初始值的变量会自动获取一个默认值null。

        2.一切皆为对象,对象的默认值是null。

3.1.4 私有变量

        与Java不同,Dart没有关键字public、protected和private。如想设置私有变量或函数,则变量和函数名以下划线(_)开头

3.1.5 final和const

        表示不可改变

        const 变量是一个编译时常量,final变量在第一次使用时被初始化

        相同点:

                1、声明的类型可以省略

                2、初始化后不能再赋值

                3、不能和var同时使用

        不同点:

                1、类级别常量,使用static const

                2、const可使用其他const 常量的值来初始化其值

                3、使用const赋值声明,const可以省略

                4、可以更改非final、非const变量的值。即使曾经具有const值

                5、const导致的不可变性是可以传递的

                6、相同的const常量不会再内存中重复创建

                7、const需要是编译时常量

3.2 基本数据类型

3.2.1 Number

3.2.1.1 说明

数值型里面有包含了int型和doubule两种类型,这两种和Java类似,其中int是整数型,double是64-bit双精度浮点数,这两种都是Number类型的子类。

3.2.1.2 代码案例

void main() {
  num a = 10; // 整形
  a = 20.1; // 浮点型
  print(a);// 20.1

  int i = 10;
  // i = 10.1;     // 这个地方会报错,因为将 int 型的数据改为 double 型 向下转型
  // i = int.parse('10.1'); // 字符串转换为int类型
  i = 10.1.round();// 通过round()方法将double转换为int
  print(i); // 10

  double d = 20.1;
  d = 20; // 这个地方不会报错,因为将 double 型的数据改为 int 型,向上转型
  // 向上转型 : (小范围)---》(大范围),这种属于自动转换
  // 向下转型 : (大范围)---》(小范围),这种属于强制转换
  print(d); // 20.0
}

3.2.1.3 数值型的操作

运算符: +、 - 、* 、/ 、 ~/ 、 %

常用属性: isNaN、isEven、isOdd

常用方法:abs()、round()、floor()、ceil()、toInt()、toDouble()

3.2.2 String

Dart字符串是UTF-16编码的字符序列

3.2.2.1 可以使用单引号或者双引号来创建字符

// 这两个是一样的
void main() {  
    print("This is a String");
    print('This is also a stirng');
}


//单双引号成对嵌套
void main() {
  String str = '单引号中的"双引号"';
  String str1 = "双引号中的'单引号'";
  print(str); // 单引号中的"双引号"
  print(str1); //双引号中的'单引号'

  String str2 = '单引号中的 \'单引号\' ';
  String str3 = "双引号中的 \"双引号\" ";
  print(str2); //单引号中的 '单引号'
  print(str3); //双引号中的 "双引号"
}

3.2.2.2 字符串拼接

void main() {
  String s1 = "First string.....";
  String s2 = "   Second string";
  print(s1 + s2); // First string.....   Second string
  
  // 使用空格即可拼接字符串
  // 使用的是空格拼接,多个空格也可以
  String str1 = '单引号空格字符串' '拼接' '~'; // 单引号字符串空格拼接~
  
  // 使用换行符以及空格
  String str2 = '单引号符串'
      '换行了'
      '再加空格'
      '拼接'; // 单引号符串换行了再加空格拼接

  // 单双引号 空格拼接
  String str3 = "单双引号空格字符串" '拼接' "~"; // 单双引号字符串空格拼接~

  // 单双引号 换行符以及空格
  String str4 = "单双引号符串"
      '换行了'
      '再加空格'
      '拼接'; // 单双引号符串换行了再加空格拼接
  
  // 下面这两种情况会报错
  // String blockStr4 = '单引号''''空格';
  // String blockStr5 = "双引号""""空格";
}

3.2.2.3 字符插值

${exprsssion},如果表达式是一个标识符,可以省略{},如果表达式的结果为一个对象,Dart会调用对象的toString()函数来获取一个字符串。

代码

void main() {
  String s1 = "First string.";
  print("String 后面拼接 $s1");// String 后面拼接 First string.

  print("The sum of 1 and 1 equals ${1 + 1}.");// // The sum of 1 and 1 equals 2.
}

3.2.2.4 多行显示

1、使用双引号创建多行字符

var s = 'Firtst'
  'Second'
  "Third";
   print(s);// FirtstSecondThird

还可以使用(’)和(")

2、使用三引表示多行字符

var multilineString = """This is a
   multiline string
   consistiong of
   multiple lines""";
  print(multilineString);
/*  This is a
   multiline string
   consistiong of
   multiple lines */

3.2.2.5 使用r前缀创建“原始raw”字符串

String s4 ="adbchi\ndfafa";
  print(s4);// 转译 /n

  String s5 =r"adbchi\ndfafa";
  print(s5);// 不转译 /n

  //输出的结果
  adbchi
  dfafa
  adbchi\ndfafa

3.2.3 Bool

Dart的bool和Java类似只有两种类型,一种是true一种是false,但是,不同的是bool对象未初始化的默认值是null。

3.2.4 List

3.2.4.1 实例化数组

// 使用构造创建
  var list = new List();

  //创建一个int类型的list
  List intlist = [1, 2, 3];

  // 创建一个常量List, 不可以改变的List
  List constList = const[10, 7, 23];

3.2.4.2 Dart就可以直接打印list包含list的元素,java中直接打印list结果是地址值。

var list = [0, 1, 2, 3, 4, 5, 6];

print(list); // [0, 1, 2, 3, 4, 5, 6]

3.2.4.3 Dart中List的下标索引和java一样都是从0开始。

3.2.4.4 Dart中List也支持泛型,这点和java一样,同时还可以进行泛型的判断。

var list1 = List<String>();

print(list1 is List<String>); // true 这里的 is 是一种类型判断

3.2.4.5 有增删改查的操作,支持倒叙,自带顺序,洗牌,可以使用+将两个List合并。

var list = [0, 1, 2, 3, 4, 5, 6];   print(list);   var list2 = [7, 8, 9, 10, 11];   print(list + list2); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

3.2.4.6 数组中的常用操作

//  在数组中可以存放多个不同类型的对象
  var list = [1, 2, 3, 'Flutter', true];
  print(list);      // 输出的结果:[1, 2, 3, Flutter, true]

  // 修改数组下标为2 的值
  list[2] = 'Dart'; // 输出的结果:[1, 2, Dart, Flutter, true]

 // 从下标0开始,下标2结束(不包括2),修改之间的值为字符a
  list.fillRange(0, 2, 'a'); // 输出的结果:[a, a, Dart, Flutter, true]

  // 获取数组的长度
  print(list.length);   // 输出的结果:5

  // 向数组中添加元素
  list.add("value"); // [a, a, Dart, Flutter, true, value]    
 var addList=['8','9'];
  list.addAll(addList);//[a, a, Dart, Flutter, true, value,8,9]

  // 向数组中的指定位置添加元素
  list.insert(1, 'element');  // [a, element, a, Dart, Flutter, true, value]
 // 向数组中指定位置加入一组元素
 list.insertAll(3, ['1','2','3','4']);// [a, element, a, 1, 2, 3, 4, Dart, Flutter, true, value]

  // 移除数组中的元素
  list.remove("value");//[a, element, a, 1, 2, 3, 4, Dart, Flutter, true]
  // 移除数组中指定的元素
  list.removeAt(1);// [a, a, 1, 2, 3, 4, Dart, Flutter, true]

  // 判断数组中是否有某个元素
  print(list.indexOf("element"));   // 输出结果:-1

  // 可以使用 sort() 函数来排序, 但是由于我们使用定义的数组类型不一样,就不能使用
  var intlist = [1, 2, 5, 6 ,3];
  // 根据语法提示: List.sort([(int, int) → int compare]) → void
  intlist.sort( (a, b) =>  a.compareTo(b) );// [1, 2, 3, 5, 6]


 //数组翻转
  var newList1=list.reversed.toList();// [true, Flutter, Dart, 4, 3, 2, 1, a, a]
  var bools=list.isEmpty;//判断集合是否为空
  var bools2=list.isNotEmpty;//判断集合是否不为空
 
  var str=list.join('***');//集合转字符串 可以用任意字符拼接
 // a***a***1***2***3***4***Dart***Flutter***true
  var newList2=str.split('***');//字符串转集合
 // [a, a, 1, 2, 3, 4, Dart, Flutter, true]

3.2.4.7 遍历

var list = [1, 2, 3, 'Flutter', true]; 
//两种遍历方式
  list.forEach((element) {
    print(element);
  });
 
  for (var item in list) {
    print(item);
  }

3.2.5 Set

3.2.5.1 Dart里面的Set和Java类似,也是不能存放重复的元素,是有序的。

3.2.5.2 两种初始化方式

var setName = <dataType>{}

Set<dataType> setName ={}

3.2.5.3 和 JAVA 语言的区别

1、difference:返回set1集合里面有但是set2里面没有的元素集合

Set<String> set1 = {"1","2","3","4","5"};
Set<String> set2 = {"1","2","3"};
print(set1.difference(set2)); // {4, 5}

2、intersection:返回set1和set2的交集

Set set1 = {“1”,“2”,“3”,“4”,“5”};
Set set2 = {“1”,“2”,“3”};
print(set1.intersection(set2)); // {1, 2, 3}

3、union:返回set1和set2的并集

Set<String> set1 = {"1","2","3","4","5"};
Set<String> set2 = {"1","2","3","6"};
print(set1.union(set2)); // {1, 2, 3, 4, 5, 6}

4、 retainAll:set1只保留某些元素(要保留的元素要在原set中存在)

3.2.6 Map

3.2.6.1 创建 Map 集合

void main(){

  // 创建Map 
  var language = {'fisrt': 'dart', 'second': 'java'};

  // 创建不可变的 Map
  var constLanguage = const {'fisrt': 'dart', 'second': 'java'};

  // 通过构造器创建
  var initLanguage = new Map();
}

3.2.6.2 Map 中常用的方法

oid main(){

  // 创建Map 
  var map = {'fisrt': 'dart', 'second': 'java'};

  // 获取长度
  print(map.length);    // 输出结果:2

  // 判断是否为空
  print(map.isEmpty);     // 输出结果:false
  print(map.isNotEmpty);  // 输出结果:true

  // 获取到所有的 key
  print(map.keys);        // 输出结果:(fisrt, second)

  // 获取到所有的 values
  print(map.values);      // 输出结果:(dart, java)

  // 判断是否包含某个key
  print(map.containsKey("key"));    // 输出结果:false

  // 判断是否包含某个value
  print(map.containsValue("key"));    // 输出结果:false

  // 添加一个新的元素进去
  map['third'] = 'key';
  print(map);         // 输出结果:{fisrt: dart, second: java, third: key}

  // 循环打印 代码提示:Map.forEach((String, String) → void f) → void
  map.forEach( (key, value) =>  getMap(key, value) );
}

void getMap(key, value){
  print("key:${key}, value:${value}");
}

void main() {
  var list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

  //如果所有的数据都满足条件的就返回true,否则返回false
  var f = list2.every((value) {
    return value > 0;
  });
  print(f); // true

  //如果所有的数据至少有一项满足条件就返回true,否则返回false
  var f2 = list2.any((value) {
    return value > 10;
  });
  print(f2); // false

  //循环遍历,输出满足条件的数据
  var newList5 = list2.where((value) {
    return value > 5;
  });
  print(newList5.toList()); //[6, 7, 8, 9, 10]

  //集合进阶
  List list3 = [
    {
      'province': '河北',
      'city': ['石家庄', '廊坊', '辛集'],
    },
    {
      'province': '北京',
      'city': ['朝阳区', '海淀区', '昌平区'],
    },
    {
      'province': '山东',
      'city': ['青岛', '淄博', '济南'],
    }
  ];

  for (int i = 0; i < list3.length; i++) {
    print(list3[i]);
  }
/*   {province: 河北, city: [石家庄, 廊坊, 辛集]}
  {province: 北京, city: [朝阳区, 海淀区, 昌平区]}
  {province: 山东, city: [青岛, 淄博, 济南]} */
  for (int i = 0; i < list3.length; i++) {
    print(list3[i]['province'] + " ");

    for (int j = 0; j < list3[i]['city'].length; j++) {
      print("   " + list3[i]['city'][j]);
    }
  }
  /* 
河北 
   石家庄
   廊坊
   辛集
北京 
   朝阳区
   海淀区
   昌平区
山东 
   青岛
   淄博
   济南
    */
}

3.2.6.3 Map遍历

map.forEach((key, value) {
    print("map----"+key+' : '+value);
   });
 
 
  //forin循环输出数据
  for(var item in mapList2){
    print("----"+item);
  }

3.2.7 Runes

Runes在Dart当中是字符的UTF-32的编码

Main(){
  Runes runes = new Runes('\u{1f605} \u6211‘);
  var str1 = String.fromCharCodes(runes);  
  print(str1); // 😅 我
}

3.2.8 Symbol

Symbol标识符,主要是反射的作用,现在在mirrors模块已经被移除了。

3.3 类型转换

3.3.1 int / double

类似于 java 的类型转换

向上转型 : (小范围)—>(大范围),这种属于自动转换

向下转型 : (大范围)—>(小范围),这种属于强制转换

示例

int i = 10;
// i = 10.1;     // 这个地方会报错,因为将 int 型的数据改为 double 型 向下转型
// i = int.parse('10.1'); // 字符串转换为int类型
i = 10.1.round();// 通过round()方法将double转换为int
print(i); // 10

double d = 20.1;
d = 20; // 这个地方不会报错,因为将 double 型的数据改为 int 型,向上转型
print(d); // 20.0

3.3.2 int / string

int j = 10;
  String jstr = j.toString();
  int z = int.parse('66');
  // int z = int.parse('66.66'); // 报错,类型不匹配
  print(jstr); // 10
  print(z); // 66

3.3.3 double / string

double f = double.parse('9.9');
  double ff = double.parse('9');
  String fstr = 3.1415926.toStringAsFixed(6); // 保留6位小数
  String ffstr = 3.1415926.toString();
  print(f); // 9.9
  print(ff); // 9.0
  print(fstr); //3.141593
  print(ffstr); // 3.1415926

3.3.4 assert

assert 是语言内置的断言函数,仅在检查模式下有效

在开发过程中, 除非条件为真,否则会引发异常。(断言失败则程序立刻终止)。

示例

// 检查是否为空
var fullName = '';
assert(fullName.isEmpty);

// 为0检查
var hitPoints = 0;
assert(hitPoints <= 0);

// 检查是否为 null.
var unicorn;
assert(unicorn == null);

// 检查是否为 NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

4 逻辑运算 

4.1 与Java的区别

操作符大部分和Java相同。标红的是不同的

4.2 ?.

条件成员访问 和 . 类似,但是左边的操作对象不能为 null,例如 foo?.bar 如果 foo 为 null 则返回 null,否则返回 bar 成员。

示例

String a;
print(a?.length); // null

String a="aaa";
print(a?.length); // 3

4.3 ~/

取商操作符

被除数 ÷ 除数 = 商 … 余数,A ~/ B = C,这个C就是商。相当于Java里的 /

示例

int a = 5;
print(a ~/ 2); // 2.5
print(a / 2); // 2

4.4 as、is、is!

类型判定操作

类型判定操作符:as、is、is!在运行时判定对象类型

示例

void main() {
  //as 类型转换
  num iNum = 1;
  num dNum = 1.0;
  int i = iNum as int;
  double d = dNum as double;
  print([i, d]); // [1, 1.0]

//  String s = iNum as String;

  //is 如果对象是指定的类型返回 True
  print(iNum is int); // false
  Child child;
  Child child1 = new Child();
  print(child is Parent); // false //child is Null 
  print(child1 is Parent); // false

  //is! 如果对象是指定的类型返回 False
  print(iNum is! int); // false
}
class Child {}
class Parent {}

4.5 ..

级联操作符

连续调用多个函数以及访问成员变量。

两个点的级联语法不是一个操作符。 只是一个 Dart 特殊语法。

示例

StringBuffer sb = new StringBuffer();
  sb
    ..write('dongnao')
    ..write('flutter')
    ..write('\n')
    ..writeln('damon');
print(sb); //输出结果:
//dongnaoflutter
//damon

 5 函数区别

 5.1 定义

void main() {
  firstMethod();
  secondMethod();
  thirdMethod();
}
 
void firstMethod(){
  print('定义了一个方法');
}
 
String getPrint(){
  return '带有返回值的方法';
}
 
int thirdMethod(int x,int y){
  return x+y;//必填带参函数
}

5.1.1 其他几个特殊点

        1、可在函数内定义函数

        2、定义函数时可以省略类型

        3、支持缩写语法=> int add(int a, int b) => a + b;

5.2 可选参数

用大括号进行声明可选参数,可选参数没有顺序,可以设置默认值,不传就是默认值

5.2.1 可以选择命名参数

printer(num n, {String s1, String s2}) {
  print(n); // 75
  print(s1); // hello
  print(s2); // null
}
main() {
    printer(75, s1: 'hello');
}

5.2.2 可以选择位置参数

printer(num n, {String s1, String s2}) {
print(n); // 75
  print(s1); // null
  print(s2); // null
}
main() {
    printer(75);
}

5.2.3 可以添加默认参数

printer(num n, {String s1, String s2}) {
  print(n); // 75
  print(s1); // hello
  print(s2); // there
}
printer(num n, {String s1 = '这是默认S1', String s2})) {
  print(n); // 75
  print(s1); // 这是默认S1
  print(s2); // null
}
main() {
    printer(75);
}

5.2.4 示例

String mysteryMessage(String who, [String what, String where]){
  var message = '$who';
  if(what != null && where == null){
    message = '$message said $what';
  } else if (where != null){
    message = '$message said $what at $where';
  }
  return message;
}

main() {
  var result = mysteryMessage('Billy', 'howdy', 'the ranch');
  print(result); // Billy said howdy at the ranch
}

5.3 匿名函数

5.3.1 可以赋值给变量,通过变量调用

5.3.2 可以在其他函数当中直接调用或者传递给其他函数

5.3.3 示例

//赋值给变量
  //无参匿名函数
  var anonFunc1 = () => print('无参匿名函数');
  anonFunc1(); // 输出结果: 无参匿名函数

  //有参匿名函数
  var anonFunc = (name) => 'I am $name';
  print(anonFunc('damon')); // 输出结果:  I am damon

  //通过()调用,不推荐
  //  (()=>print('不推荐'))();

  //匿名函数传参
  List test(List list, String func(str)) {
    for (var i = 0; i < list.length; i++) {
      list[i] = func(list[i]);
    }
    return list;
  }

  var list = ['d', 'a', 'm', 'o', 'n'];
  //String * int, Dart和Python可以这样用
  print(test(list, (str) => str * 2)); //[dd, aa, mm, oo, nn] 

  //List.forEach()就用的匿名函数
  List list1 = [11, 12, 13];
  list1.forEach((item) => print('$item'));

  //返回Function对象(闭包)
  Function makeAddFunc(int x) {
    x++;
    return (int y) => x + y; // 返回的是 function 对象
  }

  var addFunc = makeAddFunc(2);
  print(addFunc(3)); // 6

void main() {
  // 函数别名
  MyFunc myFunc;
  //可以指向任何同签名的函数
  myFunc = subtsract;
  myFunc(4, 2); // subtsract: 2
  myFunc = divide;
  myFunc(4, 2); // divide: 2.0
  //typedef 作为参数传递给函数
  calculator(4, 2, subtsract); // subtsract: 2
}

// 函数的类型是Function类型,typedef就是给Function取个别名,相当于进行一次简单的封装
typedef MyFunc(int a, int b);
//根据MyFunc相同的函数签名定义两个函数
subtsract(int a, int b) {
  print('subtsract: ${a - b}');
}

divide(int a, int b) {
  print('divide: ${a / b}');
}

//typedef 也可以作为参数传递给函数
calculator(int a, int b, MyFunc func) {
  func(a, b);
}

6 流程控制语句 

6.1 概览

6.1.1 if else

6.1.2 for,forEach,for-in

6.1.3 while,do-while

6.1.4 break,continue

6.1.5 switch case

6.1.6 assert

6.1.7 大部分使用方法都是和Java相同的

6.2 for-in

var colorList = ['black','red','yellow'];   
for(var i in colorList){     
    print(i);   
}   
//输出:   
//I/flutter (31601): black   
//I/flutter (31601): red  
//I/flutter (31601): yellow

6.3 assert

assert(condition,optional,message)
 

var variable;
print(variable);
assert(variable!=null);
variable = 6;
print(variable);
//输出:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter_app/main.dart': Failed assertion: line 50 pos 10: 'variable!=null': is not true.

断言,它可以为代码执行设置条件,用于bool条件为false时中断正常的运行。

相当于throw概念,但是这里是必断

7 异常 

7.1 说明

不管是Java语言还是Dart语言,都有异常,以及异常的捕获,但是不同的是dart中的异常都是非检查异常,方法可以不声明可能抛出的异常,也不要求捕获任何异常。

Dart提供了Exception和Error类型以及一些子类型来定义异常。不过,还可以自定义异常,只要抛出非空对象作为异常即可,不要求必须是Exception和Error对象,但是一般来说都是抛出Exception和Error类型。

7.2 Exception类型

图例概览

7.3 Error类型

图例概览

7.4 Dart中处理异常的方式

7.4.1 throw抛出异常

void throwKeyword() {
  try {
    testAge(-2);
  }
  catch(error) {
    print(error);
  }
}

void testAge(int age) {
  if(age < 0){
    throw new FormatException("年龄不能小于 0");
  }
}

7.4.2 try-on处理特定类型的异常;

void onStatementBlock() {
  int x = 12;
  int y = 0;
  int res;

  try{
    res = x ~/ y;
  }
  on IntegerDivisionByZeroException {
    print("除数不能为零");
  }
}

7.4.3 try-catch处理无法预料的异常

void catchStatementBlock() {
  int x = 12;
  int y = 0;
  int res;

  try {
    res = x ~/ y;
  }
  catch(error) {
    print(error);
  }
}

7.4.4 try-on-catch处理特定类型的异常和其它无法预料的异常

void onCatchStatementBlock() {
  int x = 12;
  int y = 0;
  int res;

  try {
    res = x ~/ y;
  }
  on IntegerDivisionByZeroException catch(error) {
    print(error);
  }
}

7.4.5 try-on...catch-finally处理完异常后统一进行的操作

void finallyCatchStatementBlock() {
  int x = 12;
  int y = 0;
  int res;

  try {
    res = x ~/ y;
  }
  on IntegerDivisionByZeroException {
    print("Cannot divide by zero");
  }
  finally {
    print("Finally block executed");
  }
}

7.4.6 异常抛出/异常捕获

抛出Exception对象

        throw new FormatException('格式异常');

抛出Error对象

        throw new NullThrownError();

抛出任意非null对象

        throw '这是一个异常';

示例

try {                                                                                    
throw new NullThrownError();
//    throw new OutOfMemoryError();
  } on OutOfMemoryError {
    //on 指定异常类型
    print('没有内存了');
//    rethrow; //把捕获的异常给 重新抛出
  } on Error {
    //捕获Error类型
    print('Unknown error catched');
  } on Exception catch (e) {
    //捕获Exception类型
    print('Unknown exception catched');
  } catch (e, s) {
    //catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为StackTrace对象堆栈信息
    print(e);
    print(s);
  }
}

7.4.7 自定义异常

实例

void customException() {
  try {
    withDrawAmt(-1);
  }
  catch(e) {
    print(e.errMsg());
  }
  finally {
    print('Ending requested operation.....');
  }
}

void withDrawAmt(int amt) {
  if(amt < 0) {
    throw new AmtException();
  }
}

class AmtException implements Exception {
  String errMsg() => 'Amount should be greater than zero';
}

7.4.8 总结 

        1.Dart异常体系建立过程,比较泛化

        2.JAVA极致的精细

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__Yvan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值