Dart语法【Dart中文】可以说是Google因为为Flutter量身定做的一门语言,所以,我们之前基本上都没有接触过这门语言,在入手Flutter坑的时候,还必须了解一下Dart的语言特性。
Dart官网【Dart中文】上面已经有了很详细的说明,我这里只是见多的说说,提取一些重点,以便自己复习以及你们学习。
v
main
每一个.Dart
文件都会有一个mian()
函数,这个称之为程序的入口文件,这就像是前端ES6语法中的export
一样,都要有一个输出。其实,Dart的设计就有一点遵循前端的ES6语法,不过他还结合了一些c语言
1 | // 程序的入口文件 |
代码都可以在DartPad上面运行,你也可以自行修改代码,不过不可能需要开着VPN才可以访问这个网站。
Dart关键字
关键字的意思就不用多说了,注意上图中的关键字,在变量命名的时候不要使用就行了。
重要的概念(重要)
- 在Dart中,所有的能够使用变量引用的都是对象,每一个对象都有一个实例,包括但不限于数字,方法,字符串,null。所有的对象都集成于Object类。这个需要注意,这个和JavaScript中的变量还是有很大的差别的
- 虽然Dart是强类型语言,但变量类型是可选的因为Dart可以自动推断变量类型
- Dart支持顶层方法(如main方法),也支持类方法或对象方法,同时你也可以在方法内部创建方法
- Dart支持顶层变量,也支持类变量或对象变量
- Dart中的私有变量用
_
开头,有点像JS中我们自定义函数的时候默认_
开头的为私有变量 - Dart中变量可以以字母或下划线开头,后面跟着任意组合的字符或数字,不能使用
$
,这里面的$
一般用于字符串拼接
变量
每一种编程语言都会有变量,Dart也不例外,不过Dart的区别就是其声明变量的方式有多种。
var
最简单的就是使用var
关键字,你也可以使用dynamic
,表示没有指定变量类型
1 | var name = 'tal'; |
使用var
定义变量,最好是定义局部变量
默认值
如果你在定义了一个变量以后,同时并没有对其进行赋值,那么,这个变量最终的类型会是null
(注意不是undefined
)。
因为前面我已以及说过了,Dart中所有的变量引用都是对象。
可选类型
在声明变量的时候我们可以加上他的类型,这个是google从TS中吸取到的经验
1 | int number = 1; |
使用这种方式定义变量可以是全局变量和局部变量,但是如果是使用var
定义变量,最好是用于定义局部变量。
Dart中内置了以下几种类型
- Number
- String
- Boolean
- List ( means array )
- Map
- Rune ( 用于在字符串中表示 Unicode 字符 )
- Symbol
1 | void main() { |
需要注意的是,在Dart中,每一个语句结束必须加上 ; 以表示语句结束
final 与 const
const
就是JS中的const,声明一个变量(一般是常量),从此不再修改。这里把final
也放到这里,当然功效也是一样的
1 | void main() { |
如果你执行了上面的代码,你将会看到如下的错误
final
在声明的时候更多的声明一个变量,而 const
更多的时候声明的是一个常量,有点像JS中的 let
与 const
,例如在Flutter初始化项目的时候有一个这样的代码。
1 | class MyHomePage extends StatefulWidget { |
final 与 const的区别
final
要求变量只能初始化一次,并不要求赋的值一定是编译时常量,可以是常量也可以不是。而const
要求在声明时初始化,并且赋值必需为编译时常量final
是惰性初始化,即在运行时第一次使用前才初始化。而const
是在编译时就确定值了。
函数
Dart中的函数有三种
1 |
|
需要注意的是,Dart中函数中参数的类型需要有一定的限制,同时num
与String
是不可相加的
1 | void main(){ |
函数参数
命名参数
命名参数是有两种方式 type key
或者是 key: type
的形式,但是都必须使用 {} 括起来,例如
1 | person({String name, int age}) => print('Hello, my name is $name, i am $age.'); |
传递参数的时候使用 key: value
的形式即可。
可选位置参数
把一些方法的参数放到 []
中就变成可选 位置参数了
1 | String say(String from, String msg, [String device]) { |
不使用可选参数
1 | print(say('Bob', 'Howdy')) // 'Bob says Howdy' |
使用可选参数
1 | print(say('Bob', 'Howdy', 'smoke signal')) // 'Bob says Howdy with a smoke signal' |
参数默认值
你可以给参数指定默认值,如果传递了参数,那么取代默认值,否则使用默认值
1 | person(String name = '踏浪') => 'My name is $name' |
入口函数
每一个.dart
文件都应该有一个入口函数,即:
1 | void main(){ |
一等对象方法
可以把方法当做参数调用另外一个方法。例如:
1 | printElement(element) { |
匿名函数
同样是上面的例子
1 | var list = [1, 2, 3]; |
forEach方法中的参数函数就是一个匿名函数
函数返回值
所有的函数都有返回值,如果没有指定return语句,那么该函数的返回值为null。
操作符
Dart中的操作符在大部分语言中都是有的,可以看看下面的表格
|描述|操作符|
|—|—|
|unary postfix| expr++ expr– () [] . ?.|
|unary prefix| -expr !expr ~expr ++expr –expr |
|multiplicative| * / % ~/|
|additive| + -|
|shift| << >>|
|bitwise AND| &|
|bitwise XOR| ^|
|bitwise OR ||
|relational and type test| >= > <= < as is is!|
|equality| == != |
|logical AND| &&|
|logical OR| || |
|if null| ??|
|conditional| expr1 ? expr2 : expr3|
|cascade| ..|
|assignment| = *= /= ~/= %= += -= <<= >>= &= ^= |= ??=|
常见的就可以不用说了,主要说一下在JS中不怎么常见的。
type tset(类型判断)
- as:类型转换
- is:类型判断,如果对象是指定的类型怎返回
true
= is!:类型转换,与is
相反
1 | if (emp is Person) { // 类型检测 |
注意: 上面这两个代码效果是有区别的。如果 emp 是 null 或者不是 Person 类型, 则第一个示例使用 is 则不会执行条件里面的代码,而第二个情况使用 as 则会抛出一个异常。
赋值操作
常用的赋值操作符都是=
,dart中有一个??=
1 | a = value; // 给 a 变量赋值 |
级联操作符(cascade) (..)
级联操作有点像JQ中的链式调用,不同点是JQ的链式调用需要上一个方法返回这个对象自身,而级联操作是不需要的,使用级联操作后,自动返回自身
如果是在web前端中,我们要获取一个元素,修改他的一些属性
1 | var img = document.querySelector('img') |
如果是使用Dart中的..
操作符,可以这样写(这里只是以此为例,不一定存在前端中的document等)
1 | document.querySelector('img') |
流程控制
Dart中的流程控制与前端中的流程控制是一样的,也就以下几种
if
andif...else
for
loopswhile
anddo-while
break
andcontinue
switch
andcase
try...catch
andtry...finally
assert
还是有一些不同点的,需要注意
- 在
switch...case
语句中,case语句中的数据类型必须是跟switch中的类型一致
Dart中还有一个assert(断言),作用是:如果条件表达式结果不满足需要,则可以使用 assert 语句俩打断代码的执行。
1 | // 确保 text 不是nunll |
但是:断言只在开发环境有效,如果是生产环境,则无效
。
class 类
前端在ES6中才引入了类的概念,即使用class
关键字创建一个类
1 | class Point { |
在使用class
构建一个类的同时,在定义一个与类名字相同的方法就定义了一个构造函数,如上面的Point
类中的Point
方法。
由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作:
如下面的代码和之前的代码是完全一样的
1 | class Point { |
类的继承
如果你是用过react
进行开发前端项目,那么你一定对class ... extends ...
非常的属性,不错,Dart中也是使用extends
继承的
1 | class Human { |
由于Human类没有默认构造方法,只有一个命名构造方法 fromJson
,所以在Man类继承Human类时,需要调用父类的fromJson方法做初始化,而且必须使用Man.fromJson(Map data) : super.fromJson(data)
这种写法
重定向构造函数
有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号
调用其他构造函数。
1 | class Point { |
getters and setters
getters
和 setters
是用来设置和访问对象属性的特殊 函数。每个实例变量都隐含的具有一个 getter,
如果变量不是 final
的则还有一个 setter。
你可以通过实行 getter
和 setter
来创建新的属性, 使用 get
和 set
关键字定义 getter
和 setter
:
1 | class Rectangle { |
抽象函数(抽象类)
定义一个抽象类需要使用 abstract
关键字,然后在定义一个方法,类型是 void
,具体是实现,由子类实现
1 | abstract class Doer { |
调用一个没实现的抽象函数会导致运行时异常。
运算符重载
如果你定义了一个 Vector
类, 你可以定义一个 +
函数来实现两个向量相加。
1 | class Vector { |
枚举类
枚举类型通常称之为 enumerations 或者 enums, 是一种特殊的类,用来表现一个固定数目
的常量。使用enum
关键字定义
1 | enum Color { |
枚举类型中的每个值都有一个 index getter
函数, 该函数返回该值在枚举类型定义中的位置(从 0 开始),有点像数组的索引。
枚举类型具有如下的限制:
- 无法继承枚举类型、无法使用
mixin
、无法实现一个枚举类型 - 无法显示的初始化一个枚举类型
mixins
Mixins
是一种在多类继承中重用 一个类代码的方法。
使用 with
关键字后面为一个或者多个 mixin 名字来使用 mixin。
1 | class A { |
静态函数与变量
使用 static
关键字来实现类级别的变量和函数。
1 | class Person { |
可以看到,静态函数与变量我们可以直接调用,而不需要通过 new
实现实例后在进行处理。
Generics(泛型)
1 | var names = new List<String>(); |
上面的代码中,<...>
表示的就是这个List中每一项的类型,上面的代码中是String
,表示的就是这个List中的每一项都要是String类型,而不能是其他的类型。
泛型是什么呢?泛型就是这一个对象中的内容可以使任何的类型,通常情况下,在<>
中使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。例如<E>
使用泛型的好处:
- 正确指定泛型类型会产生更好的生成代码。
- 泛型可以减小代码的复杂度
更多的泛型知识可以点击这里查看
Dart库
使用 import
来指定一个库如何使用另外 一个库。
1 | import 'dart:html'; // 导入 web 组件库 |
更多官方库可以点击查看
我们也可以引用自己的.dart
文件,类似于 ES6 中的 import
1 | // add.dart |
在另一个文件引入
1 | import './add.dart'; |
使用 as
创建别名
1 | import 'package:lib1/lib1.dart'; |
使用 show
and hide
过滤引入内容
1 | // Import only foo. |
使用 deferred as
来延时载入库
1 | import 'package:deferred/hello.dart' deferred as hello; |
异步支持
Dart支持ES7的 async await
方法
下面的代码使用Dart从网络获取数据并打印出来
1 | import 'dart:async'; |
以上就是关于Dart
语法的简单介绍,想要了解更多,可以参阅Dart官网
注:参考文献