前言
Flutter这两年火了,最近有个自己的项目在筹备中,决定用Flutter实现,Flutter应用程序使用Dart语言开发,Dart是面向对象编程语言,由Google于2011年推出,目前最新版本是2.0,为了更好的使用Flutter进行应用开发,本文将详细介绍Dart语言的语法和特性。
重要概念
在学习Dart之前要了解一下Dart相关概念:
能够放在变量中的所有内容都是对象,每一个对象都是一个类的实例。甚至于数字、函数和null值都是丢向,并且所有对象都继承自Object类。
Dart是强类型语言,但类型标识是可选的,因为Dart可以推断类型。如果要明确说明不需要任何类型,可以使用类型dynamic
标识。
Dart支持反省,如List或者任何类型的对象列表。
Dart支持顶级函数(例如main函数),以及绑定到类或者对象的函数(分别是静态方法和实例方法)。函数内部可以创建函数(嵌套函数或者本地函数)。
Dart支持顶级变量,以及绑定到类或对象的变量(分别是静态变量和实例变量)。
与Java不通,Dart没有关键字public
、protected
和private
。如果设置私有变量或者函数,则变量和函数名以下划线——
开头。
标识符可以以字母或者下划线_
开头,后跟这些字符加数字的任意组合。
Dart有两个表达式(具有运行时值)和语句(不具有)。例如三元表达式?expr1:expr2
的值为expr1或expr2。将其余if-else语句进行比较,该语句没有任何职。语句通畅包含一个或多个表达式,但表达式不能直接包含语句。
Dart工具可以报告两种问题:告警和错误。告警知识表明您的代码可能无法正常工作,但他不会阻止你的程序执行。错误可以是编译时或者运行时。编译时错误会组织代码执行;运行时错误导致代码执行时发生异常。
关键字
任何语言都有关键字,关键字是在编程时不能使用作为标识符的单次。Dart的关键字如下:
编码时应避免使用以上单词作为标识符,如果有必要,可以使用带有上标的单词作为标识符:
带有上标1的单词是上下文关键字,仅在特定位置有含义,它们在任何地方都是有效的;
带有上标2的单词是内置标识符,它们在大多数地方是有效的,但不能用作为类和类型名称或作为一个导入前缀;
带有上标3的单词是与Dart1.0发布后添加的异步支持相关的有限的保留字符,不能在任何标记为async,async * 或sync * 的任何函数体中使用await和yield作为标识符
变量
变量的定义
可以使用var来定义变量,变量的类型可以通过变量值来推断出来
1 2 3 var name = "hi"; //String类型 var age = 18; //int类型 var high = 1.70; //double类型
如上变量定义后其类型已经确定,不可再将其他类型的值赋给变量。
1 2 var name = "hi"; //String类型 name = 3; //此处编译器会报错,name被定义赋值之后已经是一个String类型,不可再赋值int类型值
也可以使用特定类型来定义变量
1 2 String name = "bruce"; //String类型 int age = 18; //int类型
如果变量不限于单个类型,则可以使用dynamic或Object来定义变量
1 2 3 4 5 6 7 8 9 10 11 12 13 dynamic value = 18; print("value = $value"); value = "bruce"; print("value = $value"); value = 3.5; print("value = $value"); Object val = 18; print("val = $val"); val = "bruce"; print("val = $val"); val = 3.5; print("val = $val");
输出结果为:
1 2 3 4 5 6 value = 18 value = bruce value = 3.5 val = 18 val = bruce val = 3.5
变量的默认值
由于前文关于Dart的一些概念中说到过,能够放在变量中的所有内容都是对象,所以如果一个变量没有初始化值,那它的默认值就为null。
1 2 3 4 5 6 7 8 int value1; print("value1 = $value1"); bool value2; print("value2 = $value2"); var value3; print("value3 = $value3"); dynamic value4; print("value4 = $value4");
输出结果为:
1 2 3 4 value1 = null value2 = null value3 = null value4 = null
final 和 const
如果不打算更改变量,可以使用final或者const。一个final变量只能被设置一次,而const变量是编译时常量,定义时必须赋值。
1 2 3 4 5 6 7 8 9 10 11 // Person类 class Person { static const desc = "This is a Person class"; //必须定义时赋值,否则编译时报错 final name; Person(this.name); //对象初始化时赋值一次 } // 定义一个Person对象 Person p = Person("Bruce"); //构造函数,创建对象时设置一次name print("p.name = ${p.name}"); //可正常输出 p.name = Bruce p.name = "haha"; //编译器报错
内置类型
Dart语言支持以下类型:
numbers
包含int和double两种类型,没有像Java中的float类型,int和double都是num的子类型。
strings
Dart的字符串是一系列UTF-16代码单元。创建方法如下:
1 2 3 4 5 6 String str1 = "hello"; //可以使用单引号或双引号 print("str1 = $str1"); String str2 = """Hi,Bruce This is Xiaoming. """; //使用带有单引号或双引号的三重引号可以创建多行字符串 print("str2 = $str2");
输出结果为:
1 2 3 str1 = hello str2 = Hi,Bruce This is Xiaoming.
booleans
Dart有一个名为bool的类型,只有两个对象具有bool类型:true和false,他们都是编译时常量。
lists
和其他编程语言常见的集合一样,Dart中使用的集合是数组或有序的对象组。Dart中数组是List对象。
1 2 List arr = ["Bruce", "Nick", "John"]; print("arr = $arr");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Map map = { "name": "Bruce", "age": 18, "high": 1.70 }; print("map = $map"); print("map['name'] = ${map['name']}"); var map1 = { 1: "hi", 2: "hello", 3: "yep" }; print("map1 = $map1"); print("map1[1] = ${map1[1]}");
输出结果为:
1 2 3 4 map = {name: Bruce, age: 18, high: 1.7} map['name'] = Bruce map1 = {1: hi, 2: hello, 3: yep} map1[1] = hi
runes
符文是字符串的UTF-32代码点。在字符串中表示32位Unicode值需要特殊语法,常用方法是 \uXXXX,其中XXXX是4位十六进制值,比如小心心(♥)是\u2665。要指定多于或少于4个十六进制数字,请将值放在大括号中。 比如,微笑(😆)是\u{1f600}。
1 2 3 4 5 6 String smile = '\u{1f600}'; print("微笑:$smile"); Runes input = new Runes( '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); print(String.fromCharCodes(input));
输出结果为
函数
Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function。这意味着函数可以分配给变量或作为参数传递给其他函数。
定义方法
和绝大多数编程语言一样,Dart函数通常的定义方式为
1 2 3 String getName() { return "Bruce"; }
如果函数体中只包含一个表达式,则可以使用简写语法
1 String getName() => "Bruce";
可选参数
Dart函数可以设置可选参数,可以使用命名参数也可以使用位置参数。
命名参数,定义格式如 {param1, param2, …}
1 2 3 4 5 6 7 8 9 10 11 12 13 // 函数定义 void showDesc({var name, var age}) { if(name != null) { print("name = $name"); } if(age != null) { print("age = $age"); } } // 函数调用 showDesc(name: "Bruce"); // 输出结果 name = Bruce
位置参数,使用 [] 来标记可选参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 函数定义 void showDesc(var name, [var age]) { print("name = $name"); if(age != null) { print("age = $age"); } } // 函数调用 showDesc("Bruce"); // 输出结果 name = Bruce
默认值
函数的可选参数也可以使用 = 设置默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 函数定义 void showDesc(var name, [var age = 18]) { print("name = $name"); if(age != null) { print("age = $age"); } } // 函数调用 showDesc("Bruce"); // 输出结果 name = Bruce age = 18
mian函数
和其他编程语言一样,Dart中每个应用程序都必须有一个顶级main()函数,该函数作为应用程序的入口点。
函数作为参数
Dart中的函数可以作为另一个函数的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 函数定义 void println(String name) { print("name = $name \n"); } void showDesc(var name, Function log) { log(name); } // 函数调用 showDesc("Bruce", println); // 输出结果 name = Bruce
匿名函数
1 2 3 4 5 6 7 8 9 10 11 12 // 函数定义 void showDesc(var name, Function log) { log(name); } // 函数调用,匿名函数作为参数 showDesc("Bruce", (name) { print("name = $name"); }); // 输出结果 name = Bruce
嵌套函数
Dart支持嵌套函数,也就是函数中可以定义函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 函数定义 void showDesc(var name) { print("That is a nested function!"); //函数中定义函数 void println(var name) { print("name = $name"); } println(name); } // 函数调用 showDesc("Bruce"); // 输出结果 That is a nested function! name = Bruce
运算符
下面就对一些对于Java或Objective-C来说未使用过的运算符通过代码来做个介绍。
1 2 3 4 5 6 7 8 9 10 11 //定义类 class Person { var name; Person(this.name); } // 调用 Person p; var name = p?.name; //先判断p是否为null,如果是,则name为null;如果否,则返回p.name值 print("name = $name"); // 输出结果 name = null
1 2 3 4 5 6 7 // 代码语句 var num = 10; var result = num ~/ 3; //得出一个小于等于(num/3)的最大整数 print("result = $result"); // 输出结果 result = 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // 类定义 class Banana { var weight; Banana(this.weight); } class Apple { var weight; Apple(this.weight); } // 调用 dynamic b = Banana(20); (b as Banana).weight = 20; // 正常执行 print("b.weight = ${(b as Banana).weight}"); (b as Apple).weight = 30; // 类型转换错误,运行报错 print("b.weight = ${(b as Apple).weight}"); //输出结果 b.weight = 20 Uncaught exception: CastError: Instance of 'Banana': type 'Banana' is not a subtype of type 'Apple'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 函数和类代码定义 getFruit() => Banana(20); // 获取一个水果对象 class Banana { var weight; Banana(this.weight); } class Apple { var color; Apple(this.color); } // 调用 var b = getFruit(); if(b is Apple) { //判断对象是否为Apple类 print("The fruit is an apple"); } else if(b is Banana) { //判断水果是否为Banana类 print("The fruit is a banana"); } // 输出结果 The fruit is a banana
1 2 3 4 5 6 7 8 9 10 11 12 // 操作代码块 String name; String nickName = name ?? "Nick"; //如果name不为null,则nickName值为name的值,否则值为Nick print("nickName = $nickName"); name = "Bruce"; nickName = name ?? "Nick"; //如果name不为null,则nickName值为name的值,否则值为Nick print("nickName = $nickName"); // 输出结果 nickName = Nick nickName = Bruce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 类定义 class Banana { var weight; var color; Banana(this.weight, this.color); void showWeight() { print("weight = $weight"); } void showColor() { print("color = $color"); } } // 调用 Banana(20, 'yellow') ..showWeight() ..showColor(); // 输出结果 weight = 20 color = yellow
控制流语句
Dart中的控制流语句和其他语言一样,包含以下方式
if and else
for循环
while和do-while循环
break和continue
switch-case语句
以上控制流语句和其他编程语言用法一样,switch-case有一个特殊的用法如下,可以使用continue语句和标签来执行指定case语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var fruit = 'apple'; switch (fruit) { case 'banana': print("this is a banana"); continue anotherFruit; anotherFruit: case 'apple': print("this is an apple"); break; } // 输出结果 this is an apple
异常
Dart的异常捕获也是使用try-catch语法,不过与java等语言稍有不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 定义一个抛出异常的函数 void handleOperator() => throw Exception("this operator exception!"); // 函数调用 try { handleOperator(); } on Exception catch(e) { print(e); } finally { // finally语句可选 print("finally"); } // 输出结果 Exception: this operator exception! finally
类
Dart是一种面向对象的语言,具有类和基于mixin的继承。同Java一样,Dart的所有类也都继承自Object。
构造函数
Dart的构造函数同普通函数一样,可以定义无参和有参,命名参数和位置参数,可选参数和给可选参数设置默认值等。Dart的构造函数有以下几个特点:
可以定义命名构造函数
可以在函数体运行之前初始化实例变量
子类不从父类继承构造函数,定义没有构造函数的子类只有无参无名称的构造函数
子类定义构造函数时默认继承父类无参构造函数,也可继承指定有参数的构造函数;
命名构造函数和函数体运行前初始化实例变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 类定义 class Tree { var desc; // 命名构造函数 Tree.init() { desc = "this is a seed"; } // 函数体运行之前初始化实例变量 Tree(var des) : desc = des; } // 构造函数调用 Tree t = Tree.init(); print("${t.desc}"); Tree t1 = Tree("this is a tree"); print("${t1.desc}"); // 输出结果 this is a seed this is a tree
构造函数继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // 类定义 class Fruit { Fruit() { print("this is Fruit constructor with no param"); } Fruit.desc(var desc) { print("$desc in Fruit"); } } class Apple extends Fruit { Apple():super() { print("this is Apple constructor with no param"); } // 默认继承无参构造函数 Apple.desc(var desc) { print('$desc in Apple'); } } // 构造函数调用 Apple(); Apple.desc("say hello"); // 输出结果 this is Fruit constructor with no param this is Apple constructor with no param this is Fruit constructor with no param say hello in Apple
mixin继承
mixin是一种在多个类层次结构中重用类代码的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // 类定义 class LogUtil { void log() { print("this is a log"); } } class Fruit { Fruit() { print("this is Fruit constructor with no param"); } } class Apple extends Fruit with LogUtil { Apple():super() { print("this is Apple constructor with no param"); } } // 调用 Apple a = Apple(); a.log(); //可执行从LogUtil继承过来的方法 // 输出结果 this is Fruit constructor with no param this is Apple constructor with no param this is a log
泛型
Dart和java一样,支持泛型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // 类定义 class Apple { var desc; Apple(this.desc); void log() { print("${this.desc}"); } } class Banana { var desc; Banana(this.desc); void log() { print("${this.desc}"); } } class FruitFactory<T> { T produceFruit(T t) { return t; } } // 调用 FruitFactory<Banana> f = FruitFactory<Banana>(); Banana b = f.produceFruit(Banana("a banana")); b.log(); FruitFactory<Apple> f1 = FruitFactory<Apple>(); Apple a = f1.produceFruit(Apple("an apple")); a.log(); // 输出结果 a banana an apple
写在最后
本文主要针对Dart不同于其他编程语言的一些语法特性进行了分析和举例,相信读过文本之后大家会对Dart语法有个很系统的了解,后边我们就可以开启Flutter应用开发之旅了。
本文转载自微信公众号:Flutter编程智能 ,这篇文章对我迅速了解Dart语言有很大的帮助,值得推荐!