Dart语法基础
Dart语法基础
Dart语言简介
Dart是Google推出的一门编程语言,最初是希望取代Javascript运行在浏览器端,后台慢慢发展成可以开发Android、iOS和web端APP的一门高质量的编程语言,目前Dart的版本是Dart2。
Dart语言特性
1 | Productive |
Dart语法简介
官网上对于Dart的语法也有详细介绍,不过是全英文的,如果对英文没有什么阅读障碍,可以直接移步官方文档。
下面我们通过Android Studio作为开发工具来一起了解Dart的语法基础。

新创建的Flutter项目,Dart代码主要在 lib/main.dart文件中,由于本篇主要讲的是Dart的语法,故暂时不看main.dart文件,在lib目录下我们创建一个新的.dart文件grammar.dart,如图:

然后我们在grammar.dart中键入以下代码
1 | // Define a function. |
这段代码一些基本的用法,基本所有的语言都通用的语法:
1 | // This is a comment. |
1 | int |
1 | 42 |
1 | print() |
1 | 'xxx' 或者 “xxx” |
1 | $variableName 或者 ${expression} |
1 | main() |
1 | var |
Dart重要概念
- 一切皆对象,无论数字、函数、和null都是对象。所有对象都继承自[Object]类。
Dart是强类型语言,但是类型声明可选,因为Dart可以推断类型。(类似Swift)
Dart支持通用类型,如List
(整数列表)或List (任何类型的对象列表)。 - Dart支持顶级函数(如main()),以及绑定到类或对象(分别是静态方法(static)和实例(instance)方法)的函数。您还可以在函数(嵌套或局部函数)中创建函数。
- 类似地,Dart支持顶级变量,以及绑定到类或对象(静态和实例变量)的变量。实例变量有时被称为字段或属性。
- 与Java不同,Dart没有公开、保护和私有的关键字。如果标识符以下划线(_)开头,则该标识符对其库是私有的。有关详细信息,请参见[库和可见性]。
- 标识符可以以字母或下划线(_)开头,然后是这些字符加上数字的任何组合。
- 有时候,某事物是一个表达(expression )还是一个语句(statement)是很重要的,所以这两个词要准确。
- Dart工具可以报告两种问题:警告和错误。警告只是表明您的代码可能不工作,但它们不会阻止您的程序执行。错误可以是编译时错误,也可以是运行时错误。编译时错误阻止了代码的执行;运行时错误导致代码执行时引发异常。
Dart变量
声明变量有多种方式:
1 | main(){ |
默认值
未初始化的变量的初始值为null。
Final 和 const修饰符
如果您从未打算更改一个变量,请使用final或const修饰他,而不是使用var或其他变量类型。最终变量只能设置一次;const变量是一个编译时常数。(Const变量是隐式最终变量。)最终的顶级或类变量在第一次使用时被初始化。
注意:实例变量可以是final,但不能是const。[实例变量定义在对象一级,它可以被类中的任何方法或者其他类中的方法访问,但是不能被静态方法访问。]
1 | Sample: |
你无法更改final变量的值:
1 | name = 'KAE'; //Error:a final variable can only be set once. |
对于想要在编译时确定并且不再变的变量,使用const。如果const变量位于类级别,则将其标记为静态const。在声明该变量时,将该值设置为编译时常量,例如数字或字符串字面量、const变量或常量数字算术运算的结果:
1 | const bar = 1000000; // Unit of pressure (dynes/cm2) |
const关键字不只是声明常量变量。您还可以使用它来创建常量值,以及声明创建常量值的构造函数。任何变量都可以赋一个常量值。
1 | var foo = const []; |
您可以从const声明的初始化表达式中省略const,如上面的baz。
您可以更改一个非final的非const变量的值,即使它曾经有一个const值:
1 | foo = [1, 2, 3]; // Was const [] |
你不能改变const变量的值:
1 | baz = [42]; // Error: Constant variables can't be assigned a value. |
Final和Const的区别:
- 区别一:
final要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而const要求在声明时初始化,并且赋值必需为编译时常量。 - 区别二:
final是惰性初始化,即在运行时第一次使用前才初始化。而const是在编译时就确定值了。
内建类型
Dart有以下几种内建的数据类型:
- numbers
- strings
- booleans
- lists (also known as arrays)
- maps
- runes (for expressing Unicode characters in a string)
- symbols
下面用一段代码来演示以上各类数据类型:
1 | main() { |
函数
Dart是一种真正的面向对象语言,所以即使函数也是对象,具有类型和功能。这意味着函数可以分配给变量或作为参数传递给其他函数。您还可以像调用函数一样调用Dart类的实例。
1 | bool isNoble(int atomicNumber) { |
对于只包含一个表达式的函数,可以使用简写语法:
1 | // =>可以替代return |
可选参数
可选的命名参数
在定义函数时,使用{param1, param2,…}来指定命名参数:
1 | /// Sets the [bold] and [hidden] flags ... |
在调用函数时,可以使用paramName: value来指定命名参数。例如:
1 | enableFlags(bold: true, hidden: false); |
可以使用@required说明它是一个必传的参数:
1 | const Scrollbar({Key key, Widget child}) |
可选位置参数
在[]中包装一组函数参数,标记为可选的位置参数:
1 | String say(String from, String msg, [String device]) { |
###默认参数值
函数可以使用=来定义命名和位置参数的默认值。如果没有提供默认值,则默认值为null。
1 | /// Sets the [bold] and [hidden] flags ... |
匿名函数
大多数函数都被命名,如main()或printElement()。你也可以创建一个没有函数名称的函数,这种函数称为匿名函数。
1 | test(Function callback) { |
运算符
| 描述 | 操作符 | ||
|---|---|---|---|
| 一元后置操作符 | expr++ expr– () [] . ?. | ||
| 一元前置操作符 | -expr !expr ~expr ++expr –expr | ||
| 乘除运算 | * / % ~/ | ||
| 加减运算 | + - | ||
| 移位运算 | << >> | ||
| 按位与 | & | ||
| 按位异或 | ^ | ||
| 按位或 | \ | ||
| 关系和类型测试 | >= > <= < as is is! | ||
| 相等 | == != | ||
| 逻辑与 | && | ||
| 逻辑或 | \ | \ | |
| 是否为null | ?? | ||
| 天健判断(三元运算) | expr1 ? expr2 : expr3 | ||
| 级联 | .. | ||
| 赋值 | = *= /= ~/= %= += -= <<= >>= &= ^= |
1 | main() { |
..运算符(级联操作)
1 | class Person { |
可以看出..调用某个对象的方法(或者成员变量)时,返回值是这个对象的本身,所以你可以接着使用用..调用这个对象的其他方法。
流程控制语句
您可以使用以下任何一种方法来控制Dart代码的流:
- if 和 else
- for循环
- while和do-while循环
- break和continue
- switch和case
- assert
你也可以使用try-catch和throw来对控制流程作出改变。
类
Dart是一种面向对象的语言,具有类和基于mixin的继承。每个对象都是一个类的实例,所有的类都是Object的子类。基于mixin的继承意味着,尽管每个类(除了Object)都只有一个超类,但类主体可以在多个类层次结构中重用。
Dart中的类没有访问控制,所以你不需要使用private、protected、public等修饰成员变量或成员函数,一个简单的类如下代码所示:
1 | class Person { |
上面的Person类中有3个成员变量,一个构造方法和一个成员方法,看起来比较奇怪的是Person的构造方法,里面传入的3个参数都是this.xxx,而且没有大括号{}包裹的方法体,这种语法是Dart比较独特而简洁的构造方法声明方式,它等同于下面的代码:
1 | Person(String name, int age, String gender) { |
使用类成员
使用点号(.)引用实例变量或方法:
1 | main (){ |
为避免最左操作数为空时出现异常,使用 ?.代替 .来使用:
1 | // If p is non-null, set its y value to 4. |
类的继承
Dart中使用extends关键字做类的继承,如果一个类只有命名的构造方法,在继承时需要注意,如下代码:
1 | class Student extents Person{ |
类的成员方法
一个类的成员方法是一个函数,为这个类提供某些行为。上面的代码中已经有了一些类的成员方法的定义,这些定义方式跟Java很类似,你可以为某个类的成员变量提供getter/setter方法,如下代码:
1 | class Rectangle { |
抽象类和抽象方法
使用abstract修饰一个类,则这个类是抽象类,抽象类中可以有抽象方法和非抽象方法,抽象方法没有方法体,需要子类去实现,如下代码:
1 | abstract class Doer { |
枚举类
使用 enum关键字定义一个枚举类
1 | enum frame {x, y, width, height} |
mixins
mixins是一个重复使用类中代码的方式,比如下面的代码:
1 | class A { |
静态成员变量和静态成员方法
使用static关键字修饰类的成员变量和成员方法
泛型
泛型通常是类型安全所必需的,他们对于写出严谨高质量的代码是很有用的:
适当地指定泛型类型可以生成更好的代码。
1
2
3var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error您可以使用泛型来减少代码重复。
1
2
3
4
5//T是替代类型。它是一个占位符
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
库
使用库
使用import来指定如何在另一个库的范围中使用来自一个库的命名空间。例如,Dart web应用程序通常使用Dart:html库,它们可以这样导入:
1 | import 'dart:html'; |
导入一个库仅仅需要提供库的URI。对于内置库,URI具有特定的形式(dart:scheme)。对于其他库,可以使用文件路径或者包:scheme的形式。包:scheme形式指定包管理器(如pub工具)提供的库。例如:
1 | import 'package:test/test.dart'; |
注意:URI表示统一资源标识符。url(统一资源定位器)是一种常见的URI
###指定一个库前缀
如果您导入两个具有冲突标识符的库,那么您可以为一个或两个库指定一个前缀。例如,如果library1和library2都有一个Element类,那么你可以用以下的方法:
1 | import 'package:lib1/lib1.dart'; |
只导入库的一部分
1 | // Import only foo. |
懒加载库
延迟加载(也称为懒加载)允许应用程序在需要时按需加载库。以下是一些您可能使用延迟加载的情况:
- 减少应用程序的初始启动时间。
- 例如,要执行A/B测试——尝试算法的其他实现。
- 加载很少使用的功能,如可选屏幕和对话框。
要延迟加载库,必须首先使用deferred as进行导入。
1 | import 'package:greetings/hello.dart' deferred as hello; |
当您需要库时,使用库的标识符调用loadLibrary()。
1 | Future greet() async { |
