Flutter(三)——一篇文章掌握Dart语言的用法

举报
择城终老 发表于 2021/07/26 23:36:18 2021/07/26
【摘要】 本文目录 Hello World变量与常量变量常量内置类型Number(数值型)String(字符串)Boolean(布尔型)List(列表)Map(键值对)dynamic和Object 运算符异常捕获函数Functionmain函数可选参数与必传递参数可选的位置参数默认参数函数作为参数传递函数作为变量 异步编程Future是什么?async和await继承,接...

Hello World

作为重新认识新语言的常规套路,每个程序员都不可避免的需要经历Hello World的历练,今天学习Dart语言也不例外,所以我们先来用Dart语言,输出Hello World:

void main(){
	print("Hello World")
}

  
 
  • 1
  • 2
  • 3

比较与Java语言来说,Dart语言输出Hello World要简练许多,当然还是比Python的代码要多一点,你可以将这段程序用文本文件输入后, 将txt后缀改成dart后缀,然后在命令行中输入"dart 文件名",就可以打印出来了,如下图所示:
在这里插入图片描述

变量与常量

变量

Dart语言在声明变量的时候与JavaScript一致,都是通过var关键字定义,然后可以接着给这个变量设置不同的值,默认为null。

这里博主有必要强调一点,Dart语言是一门强类型语言,在第一次赋值的时候,如果已经确定了字符串类型,则不能更改为其他类型,这一点与JavaScript弱类型语言不一样,如果你是从JavaScript转过来,需要额外的注意,当然Dart第一次赋值为其他类型是可以变更的。

常量

对于已经学习过其他各种语言的小伙伴来说,这里算是非常基础的知识,一般的就不介绍了,我们直接来看代码:

//这里声明的是一个变量
var num;
num=11;
print("小明的年龄是 $num 岁");

//开始声明不是字符串,可以变更类型
num='20';
print(num);

//这里定义了一个常量,只能被赋值一次,与Java语言一致
final c=30;
print(c);


const d=50;
print(d);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里,我们可以看到,用了const定义了d,那么const与final有什么不同?

在Dart语言中,const变量是一个编译时常量,可以理解为const变量是一个隐式的final,但实例变量可以是final,不能是const。而且常量如果是类级别的,可以使用static const,例如:static const PI=3.1415。

内置类型

Dart语言内置了一些类型,具体如下:

(1)Number(数值型)

(2)String(字符串)

(3)Boolean(布尔型)

(4)List(列表)

(5)Map(键值对)

(6)Runes(符号字符)

(7)Symbols(标识符)

Number(数值型)

在Dart语言中,数值型分为整形int与浮点型double,可以用num,int,double声明使用。我们直接来看一段代码:

num a=10
a=10.2

  
 
  • 1
  • 2

可以看到,用num声明的变量也是int类型,而且可以修改为double类型,那么这里就有一个灵魂拷问了,反过来,把double类型改为int型可以吗?

答案是不可以,看一下源码我们就很好理解了,源码如下:

abstract class int extends num
abstract class double extends num

  
 
  • 1
  • 2

数值型运算

这里博主列举了常用的三种数值型运算操作:

(1)运算符:+,-,*,/,~/,%(加,减,乘,除,取整,取余)

(2)常用属性:isNaN,isEven,isOdd等

(3)常用方法:round(),floor(),ceil(),toInt(),toDouble(),abs()

这里需要注意的是,在Dart2.0中,如果我们声明的变量是double类型,但值是int型的,会自动转换为double类型,当然也可以通过toDouble()方法进行转换。

String(字符串)

在这篇博文开头,我们已经打印出来字符串Hello World,那么在Dart语言中,有哪几种创建的方式?

(1)直接使用单引号,双引号创建字符串

(2)使用三个引号或双引用创建多行字符串

(3)使用r创建原始raw字符串

字符串运算

(1)运算符:+,*,==,[]

(2)插值表达式:${expression}

(3)常用属性:length,isEmpty,isNotEmpty

(4)常用方法:contains(),subString(),startWith(),endsWith(),indexOf(),lastIndexOf(),toLowerCase(),toUpperCase(),trim(),trimLeft(),trimRight(),split(),replaceAll()

这里不需要死记硬背,大多数方法都是Java中都有的,而剩下的如果不会用,编译器也会提示你它的详细用法,所以这里博主就不再赘述。

特别注意:但是,这里还是与一点需要注意的,如果单引号嵌套单引号,或者双引号嵌套双引号需要加反斜杠进行转义

Boolean(布尔型)

在Dart语言中,布尔类型常用的地方也是在if条件中判断,Dart语言中布尔类型有四个特点:

(1)使用bool表示布尔类型

(2)布尔类型只有true和false二个值

(3)布尔值是编译时的常量

(4)可以在debug模式下,通过assert断言函数判断布尔值,如果不为真,会引发异常并终止程序往下运行,在开发的时候这点非常有用。

List(列表)

在Dart语言中,List表示集合,但其实与数组是同一个概念,使用的方式如下:

//创建List
var list=[1,2,3];
//通过构造方法创建
var list=new List();
//创建一个不可变的List
var list=const[1,2,3]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在实际的使用过程中,我们除了要创建List数组以外,还需要学会如何使用它,获取或者修改它的值,操作的代码如下:

list[0]=55;

  
 
  • 1

在Dart语言中,List的常用的方法有这些:length(),add(),insert(),remove(),clear(),indexOf(),lastIndexOf(),sort(),sublist(),asMap(),forEach(),shuffle(),这里面有些很好理解,与Java的差不多,我们特别看看下面几个方法,使用代码如下:

var list=['one','two','three'];
print(list.indexOf('one'));//获取元素所在位置索引
print(list.sublist(2));//去除前两个元素返回新的List
print(list.shuffle());//打乱List元素的顺序

  
 
  • 1
  • 2
  • 3
  • 4

Map(键值对)

在Dart语言中,Map与Java中的Map类似,都是以键值对的形式存储数据,键和值可以是任何类型的对象,每个键只能出现一次,我们来看看它的声明代码:

//第一种声明方式
Map map={'book':'zhangyue','yellow':'blue'};
//第二种声明方式
Map map=new Map();
map['book']='zhangyue';

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

同样创建一个不可变的Map,只要和上面List一样加上const就行了:

Map map=const{'book':'zhangyue','yellow':'blue'};

  
 
  • 1

在flutter中,我们还需要使用到两个方法,代码如下:

map.remove('book');//把key为book的元素溢出掉
map.clear();//清空整个Map集合

  
 
  • 1
  • 2

dynamic和Object

在Dart语言中,一切皆是对象,而且这些对象的父类都是Object。当没有明确类型时,编译的时候会根据值明确类型,例如:

var name='Liyuanjing';
Object name1='Liyuanjing';
dynamic name2='Liyuanjing';

  
 
  • 1
  • 2
  • 3

以上三种写法都没有问题,但是Dart语言不建议我们这么做。我们在实际的开发中,我们应尽量为变量确定一个类型,这样可以提高安全性,加快程序的运行速度,如果不指定类型,则在debug模式下类型会是动态的,所以博主推荐定义字符串要这样:

String name='Liyuanjing';

  
 
  • 1

上面我们还使用了dynamic,这个定义是告诉编译器,代码变量不用做类型检测,并且知道写代码的人知道自己在做什么,我们先来看一段代码:

dynamic obj='李元静';
obj['name']=27;

  
 
  • 1
  • 2

这段代码编译时可以通过,但会抛出“NoSuchMethodError”异常,为了运行的时候对类型进行检测,我们可以使用as和is关键字,代码如下:

dynamic obj=<String,int>{};
if(obj is Map<String,int>){
	obj['name']='Liyuanjing';
}
var map=obj as Map<String,int>;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

运算符

(1)三目运算符

在上面类型介绍中,我们已经介绍了一些运算符,这里我们介绍上面没有提及的运算符,以及一些要注意的事项,首先,就是Dart语言的三目运算符,这个相当的重要,经常与flutter中的state状态管理结合使用,来判断组件的状态,用法如下:

expr1 ?? expr2//如果expr1非空,则返回expr1,否则返回expr2

  
 
  • 1

我们在来看一个与Java类似的用法:

int a=20;
var va1=a>10 ? a : 0;

  
 
  • 1
  • 2

(2)~/

细心的读者,应该看到博文上面提到了一个~/运算符,这个是返回一个整数结果,取商,使用方式如下:

var va1=12~/7;
print(va1);//打印出来的是1

  
 
  • 1
  • 2

(3)级联操作符

这个有点类似一些语言的链式调用,使用过Java和JavaScript应该见的非常多,使用方式如下:

String str=(new StringBuffer()
		..write('Li ')
		..write('Yuan ')
		..write('Jing').toString());
print(str);//会打印除Li Yuan Jing

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

(4)as,is和is!

as:判断属于某种类型

is:如果对象具有指定类型,则为True

is!:如果对象具有指定类型,则为False

异常捕获

要说Dart语言有什么特殊的强大功能,我想捕获异常真的是非常的好用,比Java还要强大,我们先来看一段代码:

throw Exception('我是异常');

  
 
  • 1

我们不仅仅需要抛出异常,还要捕获异常,所以在Dart语言中,捕获异常的详细代码如下:

try{
//捕获特定类型异常
}on AuthorizationException catch(e){
//捕获特定类型异常,但不要这个对象
}on Exception{
//捕获所有异常
}catch(e){
//....
}finally{
//....
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

函数Function

Dart语言是一门面向对象语言,所以函数也是对象,并且函数的类型是Function。这点和JavaScript非常相似。在JavaScript里面Function是可以作为参数传递的,在Flutter里面,也不例外,即函数可以分配给变量或作为参数传递给其他函数,定义函数的代码如下:

bool getName(name){
	return name;
}

  
 
  • 1
  • 2
  • 3

main函数

没有应用程序都必须有一个顶层main函数,作为程序的入口,这一点和Java一样,它是应用程序的入口点。该函数返回void并具有List的可选参数。第二篇我们讲解过源码,入口函数就是这样:

void main()=>runApp(MyApp());

  
 
  • 1

可选参数与必传递参数

定义可选参数的函数,顾名思义,就是不传这些参数也可以调用函数,例如:

void getName({String name,int age}){
}

  
 
  • 1
  • 2

这里可以传递一个,也可以传递二个,也可以一个都不传递。那么必传递该怎么写呢?我们直接上代码:

void getName({@required String name,@required int age}){
}

  
 
  • 1
  • 2

必传参数用@required修饰,在Dart语言中,使用@required有利于静态代码分析器进行检查。

可选的位置参数

一个函数里面即包含可选参数,也包含必选参数,我们需要这样写:

void getName({String name,int age,[String school]}){
	if(school!=null){
		print('学校是$school');
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

默认参数

默认参数是编译时的常量,在函数的参数后面,使用“=”为参数赋值,这个有一点像JavaScript里的ES6特性,例如:

void getName({String name='李元静',int age=27}){
}

  
 
  • 1
  • 2

函数作为参数传递

既然我们开头提到了函数可以作为参数传递,我们不妨直接上代码理解:

void getName(String name){
	print(name);
}
var names=['小静','小尧','小帆'];
names.forEach(getName);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

函数作为变量

函数也可以直接赋值给一个变量,并且把这个变量作为函数来调用,代码如下:

var printName=(name){
	print(name);
};
printName('Li YuanJing');

  
 
  • 1
  • 2
  • 3
  • 4

异步编程

Dart语言和JavaScript语言的共同点是单线程,同步代码会阻塞程序,因此程序里能看到大量的异步操作,它是用Future对象来执行相关操作的,并且async函数使用await关键字时才被执行,直到一个Future操作完成,Future支持链式操作的方式,可以按顺序执行异步操作。

Future是什么?

一个Future是一个Future自身的泛型Flutter对象,它表示一个异步操作产生的T类型的结果,如果结果的值不可用,Future的类型会是Future,如果返回一个Future的函数被调用了,将会发生以下两件事:

(1)这个函数加入待完成的队列并且返回一个未完成的Future对象

(2)当这个操作结束了,Future对象返回一个值或者错误。

例如:

Future<int> future=getFuture();
future.then((value)=>handleValue(value))
	.catchError((error)=>handleError(error))
	.whenComplete()=>handlerComplete();

  
 
  • 1
  • 2
  • 3
  • 4

如果你是前端的开发人员,可以理解Future类似前端里的Promise。我们在future.then中接收异步处理结果,并根据业务需求做相应的处理。而future.catchError则用于在异步函数中捕获并处理错误。在有些业务场景下,无论是异步任务的处理结果是成功还是失败,我们都需要再进行一些处理,这时候可以使用Future的whenComplete进行回调。

async和await

当遇到需要延迟的运算(async)时,将其放到延迟运算的队列(await)中去,把不需要延迟的运算的部分先执行完,最后在来处理延迟的运算部分。但是,要使用await,就必须在有async标记的函数中运行,否则这个await会报错。

其实这个和JavaScript也很像,async和await是Future的语法糖(Syntacticsugar),解决了回调地狱(Callback Hell)的问题。

那么回调地狱又是什么?这个需要结合具体业务场景来说,比如“业务1->业务2->业务3”,这三个任务都是异步的,那么业务1成功之后调用业务1的then回调,然后业务1的then里面在调用业务2,依次类推,就形成了回调地狱。回调地狱多了之后,我们的代码会非常难看,因为需要大量的缩进,比如这种:

step1('step1').then(step1Result(){
	step2('step2').then(step2Result(){
		step3('step3').then(step3Result(){ //依次类推456....
		})
	})
})

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们刚在上面讲解了async和await是Future的语法糖,我们在使用过程中给人的感觉是在调用同步的代码。为了解决这种回调地狱,我们对以上代码结构进行了一些调整,修改后的代码如下:

steps() async{
	try{
		String step1Result=await step1('step1');
		String step2Result=await step2(step1Result);
		String step3Result=await step3(step2Result);
		//456......
	}catch(e){
		print(e);
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

从上面的代码我们可以看到,await必须被包裹在async里面,如果没有async就会报错。后续我们将通过其他章节在进行详细的使用。

继承,接口实现

在Dart语言中,继承和接口实现基本上与Java类似,但是我们需要注意以下几点:

(1)继承:构造函数不能被继承,而且在Dart语言中,没有Java中的公有与私有的修饰符,因此,可以直接访问超类中的所有变量与方法。

(2)接口实现:在Dart语言中,没有接口的修饰符,但是每个类都是一个隐式的接口,这个接口包含类里的所有成员变量与方法,当类被当作接口使用的时候,类中的方法就是接口中的方法,它需要在子类里重新被实现,而且实现的时候需要加上@override关键字。

使用方式如下:

abstract class A{
	void printA();
}

class B{
	void printB(){
	}
}

class C{
	void printC(){
		print('C');
	}
}

class SoftwareSngineer extends C implements A,B{
	@override
	void printA{
		//重写
	}
	@override
	void printB(){
		//重写
	}
}

  
 
  • 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

混合

在Dart语言中,我们有一个新的特性,那就是混合的语言特性mixins,它的作用是在类中混入其他功能,mixins最早出现在Lisp语言中。你可以这么来理解,就是在面向对象的语言中,mixins是一个可以把自己的方法提供给其他类使用,但却不需要成为其他类的父类的类,它以非继承的方式来复用类中的代码。要使用mixins,则要用关键字with来复用类中的代码,使用方式如下:

abstract class A{ factory A._(){ return null; } void printA(){ print('A'); }
}

class C with A{ @override void printA(){ print('A'); }
}

void main(){ C()..printA();
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

那我们现在就有一个疑问了,如果同时使用继承,接口实现与混合,并且@override的方法都一样,那么执行的优先级会怎么样?我们直接上代码跑一下就清楚了:

class Cat{ void show(){ print('小猫'); }
}

class Brid{ void show(){ print('小鸟'); }
}

class Owner{ void show(){ print('主人'); }
}

class person1 extends Owner with Cat,Brid{ void show(){ print('主人1养了猫和鸟'); }
}

class person2 extends Owner with Cat implements Brid{ void show(){ print('主人2养了猫和鸟'); }
}
void main(){ person1()..show(); person2()..show();
}

  
 
  • 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

如果代码如上,没有任何注释,那么会直接执行类本身的方法,输出效果如下:

在这里插入图片描述
现在我们注释调用两个person中的方法,其他代码不变:

class person1 extends Owner with Cat,Brid{ //void show(){ //print('主人1养了猫和鸟'); //}
}

class person2 extends Owner with Cat implements Brid{ //void show(){ //print('主人2养了猫和鸟'); //}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

那么现在打印出来的效果就是这样:
在这里插入图片描述
从这里我们可以看出来,假如使用了混合,继承与接口实现,那么它的执行优先级顺序是mixins->extends->implements。

泛型

在Dart语言中,泛型与Java中很相似,比如List。用尖括号括起来的就是泛型的写法。在List中,这个E代表泛型的类型,且不一定要用E表示,还可以用T,S,K等表示,我们先来简单的使用一下:

void main(){
	List animals=new List<String>();
	animals.addAll('小猫','小狗','小兔');
}

  
 
  • 1
  • 2
  • 3
  • 4

在上面代码中,我们使用了List集合来存储小动物,并且指定了List泛型,这样定义就说说明只能存储字符串类型。

Dart语言基础就这么多,重点都在后面,前面大部分只要学过其他的语言,看看根本不费劲,Dart语言是Flutter开发的主要语言,必须要掌握的哦。

文章来源: liyuanjinglyj.blog.csdn.net,作者:李元静,版权归原作者所有,如需转载,请联系作者。

原文链接:liyuanjinglyj.blog.csdn.net/article/details/103737262

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。