Flutter:Dart基础语法入门

工作上的需要,被迫上线学习Flutter,看了下文档和线上的专栏,人老了,怕容易忘记,记录下笔记,如果有错误的地方,烦请纠正。

一、Dart简介

Dart是Google在2011年10月正式发布的编程语言,起初的定位是运行在浏览器的脚本语言。是Google大神由于不满JavaScript开发的程序后期难维护问题,而新研发的一种面向对象编程语言。然而nodejs的出现,JavaScript很快覆盖了全栈,很多手机应用和桌面应用也成为了JavaScript的宿主容器。这使Dart始终不温不火,这么多年来内置Dart VM的浏览器厂家也只有Google自己的产品Chrome(现在好像已经移除)。

很多人都有疑问,为什么JavaScript那么火,而Dart的开发者那么稀缺,Flutter会选择Dart作为基础语言去研发呢?这不会提高开发者的介入成本,不利于推广吗?个人感觉应该以下几个原因:

  • Dart是Google自主研发产品,可以避免很多类似Oracle和Android的争议问题。
  • 自主研发语言,可以灵活迭代,为Flutter架构的形成做最有力的支撑。
  • Dart 寻求转型,想弯道超车进入移动开发的领域

那么Google选择了用Dart语言开发Flutter框架,除了我们分析的客观原因外,Dart本身有哪些特性是值得Flutter去选择的?

二、Dart特性

  • Dart是声明式布局语言,易于阅读和可视化,可以不通过可视化构建器,通过热重载直接真机调试。
  • 同时支持JIT(即时编译,JavaScript,Python)和AOT(运行前编译,C,C++)

Dart在开发阶段,使用了JIT编译,这可以提高它的研发效率,降低研发周期。Flutter最受欢迎的热重载,正是因为这一特性。而发布的时候使用AOT,就不用像RN那样,在JavaScript和原生中建立低效的方法调用映射,因此,Dart具有运行速度快,执行性能好的特点。

  • Drat是单线程模型,不需要像多线程那样处理资源共享和数据同步问题,这也就意味着一个函数执行,就将执行到函数结束为止,期间不会被其他Dart代码所打断。Dart的Isolate(隔离区)不会共享内存,几个单独的worker之间,通过事件循环在事件队列中进行通信(类似Node)。

三、Dart基础语法

Dart的运行依赖于Dart VM,大家可以通过安装Dart SDK,来体验Dart。安装过程以MacOS为例子,可以通过brew安装

1brew tap dart-lang/dart 2brew install dart 3 4

接着在VSCode安装Dart插件和code runner插件即可在vscode中体验Dart编程。

跟很多编程语言一样,Dart同样以main函数作为执行入口

1void main() { 2 print('hello world'); 3} 4 5

Dart变量

Dart可以通过var关键字创建变量,当使用var时,类型是通过编译器推断决定.

1var name = 'tony'; 2print(name is String); // true 3 4

在默认情况下,未初始化的变量值为null,所以我们不需要担心无法判断一个传递过来的变量是undefined还是null(JavaScript的表示泪目),所以不需要各种if else。

1var name; 2print(name); // null 3 4

Dart类型

Dart是类型安全的语言,一切皆为对象的设计思路,任何类型都是对象类型,都继承了顶层的Object。类如bool,int,null,函数,都是继承于Object。

1String name; 2print(name is Object); // true 3bool isPig; 4print(isPig is Object); // true 5int num; 6print(num is Object); //true 7void fun() {} 8print(fun is Object); //true 9 10
  • 布尔类型

在Dart中,使用bool关键字来定义布尔类型,而布尔类型只有两个值,true和false,它们都是编译时常量。

1var c1 = true; 2var c2 = false; 3print(c1 is bool); // true 4print(c2 is bool); // true 5 6
  • 数值类型

在Dart中,使用num关键字来定义数值类型,num有两个子类,分别为int代表整数类型和double代表浮点类型

1num n = 10; 2print(n is int); // true 3num m = 1.1; 4print(m is double); // true 5 6

除了常见的基本运算符,比如 +、-、*、/,以及位运算符外,你还能使用继承自 num 的 abs()、round() 等方法,来实现求绝对值、取整的功能。你会发现,这些常见的运算符都继承于num

  • 字符串类型

在Dart中,String 由 UTF-16 的字符串组成。你可以使用${}内嵌表达式在字符串中,如果是一个表示符,可以省略{}

1var name = 'chong'; 2print('my name is $name'); // my name is chong 3print('toUpperCase: ${name.toUpperCase()}'); //toUpperCase: CHONG 4 5

字符串的拼接,与JavaScript一样,Dart用“+”运算符来拼接。

1var x1 = 'chong'; 2var x2 = '...'; 3print(x1 + x2); // chong... 4 5

对与多行字符串的拼接,Dart提供了类似JavaScript的模版字符串功能。用三个单引号或者三个双引号声明

1var str = ''' 2 my 3 name 4 is 5 chong 6 '''; 7 print(str); 8 /* 9 my 10 name 11 is 12 chong 13 */ 14 15
  • 集合类型

在Dart中,集合类型包含了数组类型和字典类型,分别对应List和Map,声明和使用,都跟Javascript差不多

1 var name = ['zhangsan', 'lisi']; 2 name.add('wangwu'); 3 name.forEach((f) => print('$f')); // zhangsan lisi wangwu 4 5 var map = {"name": 'chong', "sex": 'boy'}; 6 map['n'] = 'hello'; 7 map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello 8 9

在定义name时,编译器会推断该List为List,所以如果add的是个int或者其他类型,会类型错误。同理 map 会被推断成Map<String, String>,当然,也可以从定义的时候设定类型,而避免推断错误。

1 var map = <String, String>{"name": 'chong', "sex": 'boy'}; 2 map['n'] = 'hello'; 3 map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello 4 5

Dart常量

1Dart中定义常量的关键字有两个,const和final,const的使用方法跟JavaScript的一样。const和final的区别主要是const是在编译时期已经确定的值,而final可以定义运行时的值,一旦运行结束,即不可改变。 2 3

var x = 10; var y = 2; final z = x / y; print(z); // 5.0 const h = x / y; print(h); // Error

Dart运算符

Dart的大多数运算符与其他编程语言的类似。有几个比较特殊的运算符,用来简化处理null的情况

  • ??运算符,x??y,表示x为空时,取y的值,x非空时,取x的值

1 var x; 2 var y = 10; 3 var z = x ?? y; 4 print(z); // 10 5 6
  • ?.运算符,x?.y 如果x为null,跳过该语句,避免报错

1 var x; 2 print(x?.y); // null 3 4
  • ??=运算符, x??=y,如果x为null,把y赋值给x。如果x不为null,跳过。

1 var x = 10; 2 var y = 20; 3 x ??= y; 4 print(x); // 10 5 6 var x; 7 var y = 20; 8 x ??= y; 9 print(x); // 20 10 11

在Dart中,一切皆对象,所以运算符也是对象成员函数中的一部分。当你在某些应用场景需要复写运算符时,Dart也提供了复写机制,只要通过 operator 关键字复写即可.

1class Demo { 2 var x, y; 3 Demo(this.x, this.y); 4 Demo operator +(Demo z) => Demo(x + z.x, y + z.y); 5 bool operator ==(Demo v) => v.x == x && v.y == y; 6} 7 8var x = Demo(3, 3); 9var y = Demo(2, 2); 10var z = Demo(1, 1); 11print(x == (y + z)); // true 12 13

四、函数

Dart的函数由返回值、函数名、参数、函数体4部分组成,函数也是对象,它的类型为Function,这也意味着函数可以被定义为变量和作为函数参数。

1 bool isCheck(int x, int y) { 2 return x == y; 3 } 4 5 void printBool(Function check) { 6 print('${check(1, 1)}'); 7 } 8 9 printBool(isCheck); // true 10 11

Dart函数也支持箭头表达式,使用方法跟Javascript一致。如上面的例子可以简化为

1 bool isCheck(int x, int y) => x == y; 2 3 void printBool(Function check) => print('${check(1, 1)}'); 4 5 printBool(isCheck); // true 6 7

作为集大多数语言优点为一身的编程语言,Dart设计非常灵活的函数传参设计。设计了通过{}指定传参,设置了通过[]设置可选参数。这也使Dart的代码更加简洁优雅。不会像JavaScript一样,如果函数需要三个参数,前两个为空时,必须占位。下面通过一个例子来记录一下Dart函数的传参。

1 void demo1({int x, int y}) => print('$x,$y'); 2 demo1(y: 2); // null,2 3 4 void demo2(int x, [int y]) => print('$x,$y'); 5 demo2(1); // 1,null 6 demo2(1, 2); // 1,2 7 8 void demo3(int x, int y) => print('$x,$y'); 9 demo3(1, 2); // 1,2 10 demo3(1); // Error 11 12 void demo4(int x, {int y}) => print('$x,$y'); 13 demo4(1); // 1,null 14 demo4(1, y: 2); // 1,2 15 demo4(y: 2); // Error 16 17

五、类

对象是类的实例,在Dart里,所有对象都继承了顶层的Object,Dart中的类定义,实例话,方法引用,跟JavaScript ES6差不多。差别点是Dart中通过 “_” 来表示私有,声明变量和方法时,在前面加上下划线,表示为private,没加的,表示为public。

1class Cat { 2 var color, tail; // 颜色、尾巴 3 Cat(this.color, this.tail); 4 5 printInfo() { 6 print('这是一只${color}毛发, ${tail}尾巴的猫🐱'); 7 } 8} 9 10var cat = new Cat('蓝色', '长'); 11cat.printInfo(); // 这是一只蓝色毛发, 长尾巴的猫🐱 12 13
  • 构造函数

Dart中,类的构造函数有同名构造函数和命名构造函数两种,同名构造函数,如上面代码所示,与类同名。而命名构造函数,用以下方式定义

1class Cat { 2 var color, tail; // 颜色、尾巴 3 Cat(this.color, this.tail); 4 Cat.defaut(var color) : this(color, '短'); // 重定向构造函数,用":"符号调用 5 6 printInfo() { 7 print('这是一只${color}毛发, ${tail}尾巴的猫🐱'); 8 } 9} 10 11var cat2 = Cat.defaut('白色'); 12cat2.printInfo(); // 这是一只白色毛发, 短尾巴的猫🐱 13 14
  • 复用

在面向对象编程语言中,复用是个很重要的概念,很多编程语言都有继承承,接口等概念,来实现代码的复用。Dart也不例外,Dart中,也引入了继承,接口的概念。

1class Animal { 2 var color, tail; 3 Animal(this.color, this.tail); 4 5 printInfo() { 6 print('这是一只${color}毛发, ${tail}尾巴的猫🐱'); 7 } 8} 9 10class Cat extends Animal { 11 var type = '大型'; 12 Cat(color, tail, {type}) : super(color, tail); 13 @override 14 printInfo() { 15 print('这是一只${color}毛发, ${tail}尾巴的猫🐱,属于${type}猫科'); 16 } 17} 18 19class Dog implements Animal { 20 @override 21 var color, tail; 22 @override 23 printInfo() { 24 print('这是一只小狗'); 25 } 26} 27 28var cat = new Cat("黑色", "长")..printInfo(); // 这是一只黑色毛发, 长尾巴的猫🐱,属于大型猫科 29var dog = new Dog()..printInfo(); // 这是一只小狗 30 31

除了继承和接口实现复用外,Dart还提供了Mixins方式。Mixins的中文意思是混入,就是在类中混入其他功能。在Dart中可以使用mixins实现类似多继承的功能。

1class Poultry { 2 printInfo() { 3 print('这是一种家畜'); 4 } 5} 6 7class Big with Poultry {} 8 9var big = new Big().printInfo(); // 这是一种家畜 10 11

代码交流 2021