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

news2024/12/25 14:31:25

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极致的精细

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法笔记(二)—— 认识N(logN)的排序算法

递归行为的时间复杂度估算 整个递归过程是一棵多叉树&#xff0c;递归过程相当于利用栈做了一次后序遍历。 对于master公式&#xff0c;T(N)表明母问题的规模为N&#xff0c;T(N/b)表明每次子问题的规模&#xff0c;a为调用次数&#xff0c;加号后面表明&#xff0c;除去调用之…

八股初始:RocketMQ

一、消息队列介绍 消息队列是什么 对于 MQ 来说&#xff0c;其实不管是 RocketMQ、Kafka 还是其他消息队列&#xff0c;它们的本质都是&#xff1a;一发一存一消费。 将 MQ 掰开了揉碎了来看&#xff0c;都是「一发一存一消费」&#xff0c;再直白点就是一个「转发器」。生产…

记一次上环境获取资源失败的案例

代码结构以及资源位置 测试代码 RestController RequestMapping("/json") public class JsonController {GetMapping("/user/1")public String queryUserInfo() throws Exception {// 如果使用全路径, 必须使用/开头String path JsonController.class.ge…

《计算机组成与设计》03. 计算机的算术运算

文章目录整数运算加法与减法乘法普通十进制乘法硬件中实现步骤例子乘法器的设计除法普通十进制除法硬件中实现步骤例子除法器的设计浮点数运算科学计数法、规格化数浮点表示单精度浮点数双精度浮点数移码表示法IEEE 754指数偏移值&#xff08;exponent bias&#xff09;规格化的…

计算机网络4:计算机网络体系结构

目录计算机网络体系结构1.网络模型2.每一层的代表含义2.1 OSI7层模型2.2 五层协议2.3 TCP/IP 四层协议3.数据在各层之间的传输过程4.为什么要进行分层计算机网络体系结构 1.网络模型 2.每一层的代表含义 2.1 OSI7层模型 &#xff08;1&#xff09;物理层&#xff1a;比特流–…

STC15中断系统介绍

STC15中断系统介绍✨本篇参考来源于STC官方stc15系列手册:538页- 589页。&#xff08;文末提供该摘取部分的文档资料&#xff09; &#x1f389;在官方提供的手册资料中&#xff0c;一个系列一份手册&#xff0c;手册内容涵盖了数据手册和参考手册以及例程案例。对于学习着来说…

彻底搞懂分布式系统服务注册与发现原理

目录 引入服务注册与发现组件的原因 单体架构 应用与数据分离

火遍全球的ChatGPT技术简介与主干网络代码

如果说当下最火的AI技术和话题是什么&#xff0c;恐怕很难绕开ChatGPT。各大厂商都在表示未来要跟进ChatGPT技术&#xff0c;开发在自然语言处理智能系统&#xff0c;可见其影响力。本篇博客追个热度&#xff0c;来简单的介绍下ChatGPT到底是一项什么技术&#xff0c;究竟如何完…

深入理解innodb存储格式,双写机制,buffer pool底层结构和淘汰策略

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

【网络编程】Java中的Socket

文章目录前言socket是什么&#xff1f;Java中的SocketJava实现网络上传文件前言 所谓Socket&#xff08;套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用…

kafka入门篇

文章目录前言介绍概念与说明安装启动配置命令操作创建topic查看topic列表发送消息&#xff08;启动一个生产者&#xff09;消费消息&#xff08;启动一个消费者&#xff09;查询topic信息删除topic集群关机使用报错java连接示例前言 作为入门篇&#xff0c;主要是了解Kafka的概…

在windows下载安装netcat(nc)命令

参考文章 一、netcat(nc)下载 网盘下载 netcat(nc)下载地址&#xff1a;netcat 1.11 for Win32/Win64 二、配置环境变量 在Path里添加netcat的存放路径 参数 说明 -C 类似-L选项&#xff0c;一直不断连接[1.13版本新加的功能] -d 后台执行 -e prog 程序重定向&am…

能取代90%人工作的ChatGPT到底牛在哪?

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…

Web 框架 Flask 快速入门(二)表单

课程地址&#xff1a;Python Web 框架 Flask 快速入门 文章目录&#x1f334; 表单1、表单介绍2、表单的简单实现1. 代码2. 代码的执行逻辑3、使用wtf扩展实现4、bug记录&#xff1a;表单验证总是失败&#x1f334; 表单 1、表单介绍 当我们在网页上填写账号密码进行登录的时…

Spring 面试题(一):Spring 如何处理全局异常?

❤️ 博客首页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;Spring 教程&#xff1a;从入门到精通 文章目录1、如何处理全局异常2、代码示例2.1、定义统一的“响应结果对象”2.2、…

Leetcode 回溯详解

回溯法 回溯法有“通用解题法”之称&#xff0c;用它可以系统地搜索问题的所有解。回溯法是一个既带有系统性又带有跳跃性的搜索算法。 在包含问题的所有解的解空间树中&#xff0c;按照深度优先搜索(DFS)&#xff09;的策略&#xff0c;从根结点出发深度探索解空间树。当探索…

MWORKS--同元软控MWORKS介绍、安装与使用

MWORKS--同元软控MWORKS介绍、安装与使用1 同元软控介绍1.1 同元软控简介1.2 同元软控发展历史2 MWORKS介绍2.1 MWORKS简介2.2 MWORKS产品描述3 装备数字化3.1 发展3.2 内涵3.3 系统模型发展成为产品的一部分3.4 MWORKS系统模型数据管理3.4 MWORKS为装备数字化提供的套件参考1 …

springcloud集成seata(AT)分布式事务

目录 一、 下载seata server和seata源码 二、配置启动seata 2.1 在nacos控制台&#xff0c;新建一个seata的名称空间&#xff0c;用于存放seata的专用配置 2.2 创建seata server的mysql库 2.3 在nacos上配置seata相关配置 &#xff08;seata名称空间&#xff09; 2.4 启动…

家政服务小程序实战教程08-宫格导航

小程序一般会在首页显示商品的分类&#xff0c;这类需求我们在微搭中是使用宫格导航组件来实现。 01 组件说明 宫格导航组件可以在导航配置里设置菜单&#xff0c;可以手动添加&#xff0c;也可以变量绑定 因为我们一般的分类是动态变化的&#xff0c;品类会不断的调整&#…

阿里代码规范插件中,Apache Beanutils为什么被禁止使用?

在实际的项目开发中&#xff0c;对象间赋值普遍存在&#xff0c;随着双十一、秒杀等电商过程愈加复杂&#xff0c;数据量也在不断攀升&#xff0c;效率问题&#xff0c;浮出水面。 问&#xff1a;如果是你来写对象间赋值的代码&#xff0c;你会怎么做&#xff1f; 答&#xf…