内容主要包括Dart的变量声明,基础类型,基本操作符,方法声明和使用,类声明和使用,抽象与继承,泛型和枚举。在Dar中,一切都是对象,包括数字,null,函数等。
变量
在变量只是声明没有被赋值的情况下,那么他的默认值是null,不论是数字还是bool还是字符串等其他。
变量
dart是强类型语言,与Java一样。他可以使用var
关键字声明变量,使用var
声明的变量假如已经初始化了,那么他就会推断出对应初始化的类型,假如没有初始化,那么他是属于dynamic
类型的。
对于使用dynamic
关键字声明的,他的值类型是可以一直修改的。例子如下:
1 | dynamic a = 10; |
常量
dart使用const
和final
声明常量,声明的时候可以没有类型,直接使用关键字即可,他们都只可以赋值一次.
const
,他必须是编译器常量,在编译阶段就确定的值,声明阶段就需要初始化,他除了变量声明为常量之外,还可以修饰构造方法或者一些常量数组,常量键值对等。final
,他可以是运行期,也可以是编译器的常量,他可以在声明阶段进行初始化,也可以作为类成员变量的时候,在构造方法之前进行初始化(后续再说这个,主要是使用this关键字或者是初始化列表)
1 | const a = "Hello"; |
dynamic,var,Object的区别
我们可以使用这三者修饰变量,表示动态类型,但是他们之间是有区别的。
- 假如var声明的变量进行了初始化,则后面不可修改类型,Object与dynamic可以
- dynamic可以用在修饰泛型,表示该集合/键值对/类等是动态的类型
- Object其实使用的是多态实现的。
1 | var a = 1; |
数据类型
dart内置的类型有
- 数值型,包括
num
和他的子类 - 字符串,
String
- 布尔类型,
bool
- 类别,
List
- 键值对,
Map
- 其他,
Runes
和Symbols
(这两个我们一般使用不到)
数值型
我们可以直接使用num
进行类型声明的操作,也可以使用他的两个子类
int
,整形double
,浮点型
注意int
和double
变量不能直接相互进行赋值,int
转double
使用相对应的double.parse(String)
方法才可以,反之double
转int
需要利用自带的比如向上取整,向下取整等方法转换。num
以及他的子类有实现加减乘除等操作符,也提供了一些比如判断是否是数字,是否是奇数偶数,取整,开方等方法,有一点需要注意的是/
这个操作符,他的返回值是一个double
类型,所以两个int相除是不能直接复制给一个int变量的。例子如下
1 | int a = 10; |
字符串
dart的字符串大体上与java差不多,只是他多了一种可以使用三个"""
或者三个'''
包裹起来的声明的字符串,可以跨行,还多了字符串的$
插值,他的值可以是字符串或者是表达式。他取字符串中的某一个值是通过[]
操作符实现的,在String
中有声明实现。它支持的操作运算符有+
,==
,*
,[]
。也提供与java类似的常用方法。例子如下:
1 | String a = "hi"; |
布尔类型
使用bool
声明,只有true
和false
两种值,需要注意他不能想js那样使用一些参数直接进行表达式判断,而是与java比较类似,同时,假如没有进行初始化,他的初始化是null
不是false
,没有初始化的是不能进行布尔类型是不能进行条件判断的。例如:
1 | bool b = true; |
集合List
与Java的List大体上比较的类型,他的大部分方法也与java的比较类似,List的泛型也是比较类似的,后面再说泛型的问题。例子如下:
1 | //声明方式 |
Map
键值对Map,他与Java也是比较类似的。例子代码如下:
1 | var map1 = {1:1,2:2,"3":3}; |
循环
Dart的循环与Java的大体差不多,只是switch中多了一种跳转,其他的都比较的类似。
操作运算符
与Java比较类似的就不写了,主要是Java中没有的操作符
??
他是一个二目操作符,是简化版本的三目运算符?:
,作用是假如调用者为空,则把后者赋给对应的变量,例如
1 | var a = 1; |
??=
他类似是??
的一种扩展,用于赋值运算,是二目赋值运算符,当左边值为null
时把右边值赋值给他,他不能用于变量声明的表达式中但是??
可以。
1 | var a = 1; |
?.
他是一个二目操作符,主要是用于避免空指针,他表示假如调用者为空则不执行后面。
1 | String a = "dart"; |
..
,as
,is
,is!
他们几个是属于类的操作运算符,后面在详细说用法。
方法
在Dart中,方法也是对象,他的类型是Function
。方法的一般定义
1 | ReturnType mehtodName(var a...){ |
基本方法
Dart声明方法的时候可以省略返回值类型,参数类型,省略的时候他们的类型是dymanic
的,假如只有一条语句的方法,可以使用=>
箭头函数的方式声明,方法声明的例子:
1 | void main() { |
可选参数
包括可选命名参数和可选位置参数,在方法声明的时候,一般参数需要在可选参数或者是命名参数之前,而且可选参数与命名参数不能同时作为参数类别出现。
可选命名参数
使用{}
包裹在方法参数中,调用的时候可以不传入可选参数,但是假如传入的时候需要指定可选参数的名称,使用:
后面设置对应传入的值,可选参数之间顺序可以调换,只需要名字匹配上即可。例如
1 | void main() { |
可选位置参数
可选位置参数使用[]
包裹在方法参数列表中,可选参数他的参数赋值是根据传入的参数顺序,这是他与命名参数的不同点。
1 | void main() { |
参数默认值
默认参数值只能为可选参数赋于一个默认值,不能为一般参数赋予默认值,使用=
赋值,例如
1 |
|
方法对象
这是与Java比较大的不同点,在Dart中,方法是对象,他可以把值赋予给一个变量,或者作为一个参数传入到另外一个方法中进行调用,例如
1 | void main(){ |
匿名方法
匿名方法就是一个没有函数名称的方法,他与正常方法一样,可以赋值给一个变量或者是作为参数进行传递。例如如下
1 | //方法声明一般是 |
闭包
闭包的定义是:闭包是一个方法对象,他需要定义在其他方法内部,他可以访问到外部方法(也就是闭包定义的方法)的变量并且持有他的状态。
他的作用是通过闭包方式,范围到方法的内部参数。因为一般我们无法在外部方位到方法的内部参数,不能对他进行修改/读取等,但是通过闭包的方式可以实现,我们需要在调用方法的返回参数中返回一个闭包对象,从而达到访问对应方法的内部变量的目的。例如
1 | void main() { |
类
使用class
关键字进行声明,使用new
关键字进行创建,可以省略new
。所有的类都是继承自Object
。
类的基本特点
类型属性和方法的特点:
- 属性默认生成getter和setter
- 使用final声明的属性只有getter
- 属性和方法通过
.
进行访问 - 方法不能重载,也就是不能有同名的方法,即使是返回值和参数不同。
类以及成员的可见性
- Dart的可见性以library为单位
- 默认情况下,每一个dart文件都是一个library
- 使用
_
表示私有,比如类和方法不能为外部访问的时候,我们对应的名称就以_
开头 - 使用
import
关键字导入外部类。
计算属性
计算属性,他的值是通过计算而来的,它本身不存储值,类似get/set方法,它实际上是通过计算转换到其他实例变量,他的主要是用类本身的某一个属性需要通过某一些属性计算而来,不适合使用方法来生成,因为方法对应行为,属性对应特质。比如一个矩形的面积是一个属性,通过长*宽得到,这时候可以不用方法计算得到,而是使用计算属性。
1 | //声明方式 |
构造方法
生成构造方法的方式有几种。
命名构造方法
它有以下一些特征
- 假如没有声明构造方法,则默认有一个传入参数为空的构造方法
- 假如显式声明了构造方法,则默认构造方法无效
- 以上两点与java是一样的,但是他还有一个构造方法不能重载,也就是不能声明多个名称一样传入参数不一样的构造方法
- 自声明的构造方法可以使用
this
进行相关属性的直接赋值,需要注意他是赋值在构造方法执行之前的,所以他可以用来给类的final
成员变量进行复制。
1 | void main() { |
类目.方法的构造方法
因为命名构造方法不可以重载,假如我们需要多个构造方法,则需要使用类名.方法进行声明,例如
1 | void main() { |
常量构造方法
常量构造方法是用来声明常量对象的,也就是可以在编译器就确定值的变量对象,它具有以下特征
- 构造方法必须是不可变状态,需要使用
const
修饰 - 其内部的所有变量都必须是
final
的 - 声明对象的时候,
const
可以省略。
例子如下:
1 | void main() { |
工厂构造方法
使用factory
修饰的构造方法。他可以在方法中返回对象,类似于工厂构造模式,在一个静态方法中创建返回对应的类对象一样。在factory
的构造方法中,不能使用this
关键字,只能使用类中static类型的属性和方法,但是可以调用其他构造方法,同时,使用factory
构造方法的时候,一般还需要另外一个构造方法生成对象。factory
中的返回值要么是null,要么是当前的类实例,不能是其他的。例子如下:
1 | void main() { |
初始化列表
初始化列表主要是用来设置final变量的值,当前也可以给普通的成员变量赋值,他是在构造方法执行之前执行,使用逗号分隔初始化表达式。例子如下:
1 | void main(){ |
静态变量
这个与java比较的类似,使用static
关键字进行声明。static
声明的变量属于类级别,可以使用类名.
进行调用,假如需要声明静态常量需要使用static const
进行声明。非静态的变量/方法可以访问静态的变量/方法,但是静态的变量/方法不能访问非静态的变量和方法。需要注意与java不一样的是类实例是无法调用静态变量或者是方法的。
类操作符
as
,把某个对象转为某个类型对象is
判断是否是同一个类型is!
判断非同一个类型..
类似于builder的调用
例子如下:
1 | void main() { |
对象的Call方法
他的主要作用是可以把对象作为方法使用,一般来说我们都是对象实例调用方法,现在我们通过call
方法可以实现把对象实例作为一个方法调用。
我们需要调用call
方法,则需要再类中实现call方法,我们的需要对象调用call方法传入几个参数就定义几个参数,需要返回值则在call中返回。例子如下:
1 | void main(){ |
继承
Dart与Java一样,具有多态的功能,可以父类引用指向子类对象。
子类通过extend
关键字继承父类,Dart也是单继承的语言。他继承的特性有
- 可见的成员变量和方法,不会继承构造方法。
- 子类可以复写父类的方法,getter/setter
关于子类父类的构造方法:
- 假如父类没有显示声明构造方法(也就是有参,不可以是类名.方法名),子类是隐式默认会调用父类的方法
- 假如父类重写了构造方法,子类需要显式的调用,调用的方式是:构造方法:super()父类构造方法
- 父类的构造方法是在子类构造方法执行之前开始执行。
- 如果有初始化列表,则初始化列表在父类构造反腐之前执行,而且必须是初始化列表在前,调用父类方法在后。
例子如下:
1 | void main() { |
抽象类
抽象类是使用abstract
修饰抽象类,它具有一下一些特点,
- 抽象类不能直接实例化,与java比较类似
- 抽象方法不能使用abstract修饰,只有是无实现的方法即可。
- 抽象类可以没有抽象方法,与java类似
接口
Dart的接口与java的不太一样,在Dart中,类和接口是统一的,类既可以作为一个类去使用,也可以作为一个接口被别的类以接口的形似实现,不管这类是不是抽闲类都可以作为接口去使用。
使用implement
进行接口实现,没有interface
声明。当一个具体类作为接口被别的类implement
的时候,别的类需要重写对应类的所有属性,方法,包括私有的,而且不能对方法进行super调用。
在实际中,建议是使用抽象类的方式定义一个类去作为接口,而不是一个实现类。
例子如下:
1 | void main(){ |
Mixins
由于Dart中是单继承的,假如我们需要使用多继承,或者是类似多继承的方式,就需要使用到Mixins。他是在多类继承中重用代码的一种方式。
他有以下几个特征:
- 必须是在继承的继承使用,也就是先有了一个不是继承自Object的继承类
- 作为Mixin的类不能显示的声明构造方法,包括默认的构造方法也不能显示的编写出现在代码中
- 作为Mixin的类只能继承自Object
- 使用
with
关键字接入Mixin类,多个只用逗号分隔 - 假如被继承的类与Mixin的类的方法有一样的,那么在继承类中调用该方法的时候,调用的是写在最后的Mixin类的方法。而且该方法只能是相同的,不能是重载的。
例子如下:
1 | void main() { |
关于使用Mixin类的声明还有一种简写,是针对实现类知识需要把几个类组合一起而不需要自己自定义其他的属性或者方法的时候,就可以使用,比如上面的D可以简写成下面的方式:
1 | class D = A with A,B; |
操作符的重写
操作符的重写主要是方便我们对对象或者对象之间进行操作的时候,可以对一些操作符在类中进行定义,然后调用,他的定义的方式是:
1 | 返回类型 operator 操作符(参数1,参数2...){ |
假如是复写了==
,一般还需要重写hashCode
的getter方法,这个是与java类似的。
可以复写的操作符有:
1 | < + | [] |
例子如下:
1 | void main() { |
枚举
枚举是一种有穷序列集的数据类型,比如四季,比如星期等。它使用enum
关键字进行声明。常用语代替常量,控制语句等。
他的一些特征是:
- 他的成员变量具有一个index属性,是从0开始的,然后依次按照声明顺序递增。
- 不能指定原始值,必须是从0开始的原始值。
- 不能添加方法
例子如下:
1 | void main(){ |
泛型
Dart中的泛型与Java的基本是一致的。支持类泛型和方法泛型。需要注意方法的泛型声明是在方法名称的后面,调用的时候也是在方法名称的后面增加泛型,这是与java不一样的。例子如下:
1 | void main() { |
值传递的问题
在Dart中关于值传递之后进行了修改是否会影响之前的值的问题,测试之后发现字符串,数据类型之类的不会,但是列表,自定义对象的是会的,这与java比较的类似。
1 | void main() { |
参考
本文主要是依照imooc的课程总结的,地址是:Dart编程语言入门
其他的推荐视频有B站的:Dart Flutter教程