Flutter Dart语法学习

2024-05-24 07:18
文章标签 学习 语法 flutter dart

本文主要是介绍Flutter Dart语法学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Dart

开发FlutterApp之前我们肯定要先了解Dart这门语言及语言的特性、语法等。最近看了大量的

Dart语言相关内容,本章会来简述。
目录

  • 概念及优点
  • 变量
  • 函数
  • 闭包
  • 异步支持
概念及优点:
  • Dart:
    Google及全球的其他开发者,使用 Dart 开发了一系列高质量、 关键的 iOS、Android 和 web 应用。 Dart 非常适合移动和 web 应用的开发。

1.高效

Dart 语法清晰简洁,工具简单而强大。 输入检测可帮助您尽早识别细微错误。 Dart 拥有久经考验的 核心库(core libraries) 和一个已经拥有数以千计的 packages 生态系统

2.快速

Dart 提供提前编译优化,以在移动设备和 web 上实现可预测的高性能和快速启动。

3.可移植

Dart 可以编译成 ARM 和 x86 代码,因此 Dart 移动应用程序可以在 iOS,Android 及 更高版本上实现本地运行。 对于 web 应用程序,Dart 可以转换为 JavaScript。

4.易学

Dart 是面向对象的编程语言,语法风格对于许多现有的开发人员来说都很熟悉。了解Java、JS语言 ,使用 Dart 也就很简单,也有Swift的一些特性。

5.响应式

Dart 可以便捷的进行响应式编程。由于快速对象分配和垃圾收集器的实现, 对于管理短期对象(比如 UI 小部件), Dart 更加高效。 Dart 可以通过 Future 和 Stream 的特性和API实现异步编程。

变量
  • var
    自动推断类型(这点与OC、Java不同),接收任何类型的的变量,但是一旦赋值,类型就不能改变,即本来是字符串,之后就只能是字符串(这点与JS不同)。
var a = "字符串";
//主意:如果这样就会报错,类型在第一次指定后就不能改变
a = 1;

原因:Dart是强类型语言,任何变量都有各自的类型,编译时会根据首次赋值数据的类型来推断其类型,编译结束后其类型不能更改。JS是纯粹的弱类型脚本语言,var只是变量的声明。

  • dynamic

dynamic与var一样都是关键词,声明的变量可以赋值任意类型对象。声明的变量可以在后期改变赋值类型。即本来是字符串,之后可以赋值为number等其他类型。

dynamic a = "字符串";
//不会报错
a = 1;
  • Object

Object与dynamic一样也是声明的变量可以赋值任意类型对象,声明的变量可以在后期改变赋值类型。

Object b = "hello world";
//不会报错
b = 10;

不同之处,dynamic声明的对象编译器会提供所有可能的组合,至少不会报错(但有可能运行时会因为找不到之前预制的组合,造成崩溃), 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错。

dynamic a = "";
Object b = "";
//编译器不报错,不警告。
print(a.length);
//编译器会警告报错(Object没有length的getter方法):The getter 'length' is not defined for the class 'Object'
print(b.length);

注意:dynamic可以理解为id类型,任何类型都可以转换成id(dynamic)类型,可以用id(dynamic)去接,编译器不会报错,但是在运行时可能会产生错误出现崩溃现象。

  • final

final 为运行时常量。

final修饰的常量必须在声明的时候就进行初始化,而且在初始化之后值不可变

final a = "名字";
//会报错
a = "性别";
  • const

const 为编译时常量。
const不仅仅可以声明常数变量,也可以声明常量值以及声明创建常量值的构造函数,任何变量都可以有一个常量值;

final aList = const[];
const bList = const[];
var cList = const[];这里的aList和bList就是两个空的、不可变的列表集合,而cList则是空的、可变的列表集合;
需要注意的是:cList可以重新赋值,可以改变,而aList和bList不可以重新赋值;
  • 函数
    Dart是面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征。

1.函数声明

返回类型  方法体  (参数1,  参数2, ...){方法体...return 返回值
}String getPerson(String name, int age){return name + '${age}';
}//如果返回类型不指定时,此时默认为dynamic。

2.箭头函数

对于只包含一个表达式的函数,可以使用简写语法。

getPerson(name,  age) => name+ ', $age' ; bool isNoble (int atomicNumber)=> _nobleGases [ atomicNumber ] != null ;

3.函数作为变量(方法对象)、入参

//函数作为变量
var  method1 = (str){
print(str)
};
method1("kakalala");//函数作为参数
void execute(var callbackMethod){
callbackMethod();
}
//两种
execute(() => print("xxx"));
execute(method1("kakalala"));

4.可选参数(可选位置参数、可选命名参数)

  • 可选位置参数:[param1, param2, …],可以设置默认参数
    包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面:
getPerson(String name, [int age = 99, String gender = "御姐"]){print ("name = $name, age = $age, gender = $gender");
}//getPerson() ;这种不传参是会报错的。
getPerson(null) ;
getPerson('不知火') ;
getPerson('不知火', 100);
getPerson('不知火', null,  "萝莉");

控制台输出

flutter: name = null, age = 99, gender = 御姐
flutter: name = 不知火, age = 99, gender = 御姐
flutter: name = 不知火, age = 100, gender = 御姐
flutter: name = 不知火, age = null, gender = 萝莉

注意:name参数是必须传入的,否则会报错。后边的可选位置参数如果不传会是null,传null还是会返回null。可选位置参数可以设置默认参数。

  • 可选命名参数:{param1, param2, …}
    在传入的时候,需要指定下对应的参数名,放在参数列表的最后面,用于指定命名参数。可以设置默认参数。
getPerson(String name, {int age = 100, String gender = "狼狗"}){print("name = $name, age = $age, gender = $gender");
}//getPerson() ;这种不传参是会报错的。
getPerson(null) ;
getPerson('烬天玉藻前') ;
getPerson('烬天玉藻前', age: 99 );
getPerson('烬天玉藻前', gender: "御姐" );
getPerson('烬天玉藻前', age: 99, gender: "奶狗");

控制台输出:

flutter: name = null, age = 100, gender = 狼狗
flutter: name = 烬天玉藻前, age = 100, gender = 狼狗
flutter: name = 烬天玉藻前, age = 99, gender = 狼狗
flutter: name = 烬天玉藻前, age = 100, gender = 御姐
flutter: name = 烬天玉藻前, age = 99, gender = 奶狗

注意:固定参数必须传入(那怕传个null),可选命名参数可以设置默认参数。

  • 默认参数值

默认参数值即我们在方法的参数列表上面使用 “=” 号给入一个常量值,如果没有传入该值的时候,就使用我们给入的常量值。

注意,不能同时使用可选的位置参数和可选的命名参数
//这种是不可以的,错误事例。
getPerson(String name, {int age = 100, String gender = "狼狗"}, [int age2 = 1002, String gender2 = "狼狗2"]){}
闭包

闭包是一个方法(对象),闭包定义在其它方法内部,能够访问外部方法的局部变量,并持有其状态。

void main() {// 创建一个函数add1,返回加2Function add1 = addNum(2);// 创建一个函数add2,返回加4Function add2 = addNum(4);// 2 + 3 = 5print(add1(3));// 4 + 3 = 7print(add2(3));
}// 返回一个函数对象,功能是返回累加的数字
Function addNum(int addBy){return (int i) => addBy + I;
}

控制台输出:

flutter: 5
flutter: 7
异步支持

Dart代码运行在一个单线程,如果Dart代码阻塞了—例如,程序计算很长时间,或者等待I/O,整个程序就会冻结。

Dart异步函数:Future、Stream,设置好耗时操作后返回,不会阻塞线程。

async和await关键词支持了异步编程,允许写出和同步代码很像的异步代码。

Future

Future与JS中的Promise和Swift的RXSwift非常相似,其语法也是链式函数调用,该函数异步操作执行后,最终返回成功(执行成功的操作)、失败(捕获错误或者停止后续操作),失败和成功是对立的只会出现一种。

注意:Future 的所有API的返回值都是一个Future对象,所以可以进行链式调用。

  • Future构造函数

Future(FutureOr computation())
computation 的返回值可以是普通值或者是Future对象,但是都是Future对象接收

 Future<num> future1 = Future(() {print('async call1');return 123;
});
//直接调用
future1.then((data) {//执行成功会走到这里print(data);
}, onError: (e) {print("onError: \$e");
}).catchError((e) {//执行失败会走到这里print(e);
}).whenComplete(() {//无论成功或失败都会走到这里
});Future<Future> future2 = Future((){print('async call2');return future1;
});//嵌套调用
future2.then((value) => value).then((value) => {print('222---'+value.toString())
});

控制台打印

Reloaded 1 of 499 libraries in 154ms.
flutter: async call1
flutter: 123
flutter: async call2
flutter: 222---123

注意:computation函数体中的代码是被异步执行的,与JS中Promise构造函数的回调执行时机不一样,如需要被同步执行,则使用如下这个命名构造函数:

Future.sync(FutureOr computation())

//该段代码放到上边代码之后执行
Future<num> future3 = Future.sync((){print('sync call');return 333;
});future3.then((value) => {print('sync'+'$value')
});

控制台输出

flutter: sync call
flutter: sync333
flutter: async call1
flutter: 123
flutter: async call2
flutter: 222---123

由此可见,future3(sync)方法会先执行,之后在执行之前的future1、future2.可见正常的future中的computation函数体中的代码是被异步执行的。

  • Future.then
    then中接收异步结果
Future.delayed(new Duration(seconds: 2),(){return "延迟2s执行";
}).then((data){print(data);
});
  • Future.catchError

捕获错误

Future.delayed(new Duration(seconds: 2),(){//return "延迟2s执行";throw AssertionError("Error");  
}).then((data){//执行成功会走到这里  print("success");
}).catchError((e){//执行失败会走到这里  print(e);
});

在异步任务中抛出了一个异常,then的回调函数将不会被执行, catchError回调函数将被调用;并不是只有 catchError回调才能捕获错误,then方法还有一个可选参数onError(之前介绍结构体时已经提到),我们也可以它来捕获异常:

Future.delayed(new Duration(seconds: 2), () {//return "延迟2s执行";throw AssertionError("Error");
}).then((data) {print("success");
}, onError: (e) {print(e);
});
  • Future.whenComplete

不管成功失败都要处理事件的场景,会调用此方法,比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。这种场景,有两种方法,第一种是分别在then或catch中关闭一下对话框,第二种就是使用Future的whenComplete回调:

Future.delayed(new Duration(seconds: 2),(){//return "延迟2s执行";throw AssertionError("Error");
}).then((data){//执行成功会走到这里 print(data);
}).catchError((e){//执行失败会走到这里   print(e);
}).whenComplete((){//无论成功或失败都会走到这里
});
  • Future.wait

需要等待多个异步任务都执行结束后再统一进行一些操作(比如我们有一个界面,需要先分别从两个网络接口获取数据,获取成功后,我们需要将两个接口数据进行特定的处理后再显示到UI界面上)
Future.wait就是做这件事的(类似RXswift的zip函数),它接受一个Future数组参数,只有数组中所有Future都执行成功后,才会触发then的成功回调,只要有一个Future执行失败,就会触发错误回调。

Future<List<Future>> future4 = Future.wait([// 2秒后返回结果  Future.delayed(new Duration(seconds: 2), () {return "延迟2s执行";}),// 4秒后返回结果  Future.delayed(new Duration(seconds: 4), () {return " 延迟4s执行";})
])future4.then((value) => {
print(value[0]+ value[1]);
}).catchError((e){print(e);
});

控制台输出

//等待4s输出
flutter: 延迟2s执行 延迟4s执行
  • 回调地狱(Callback Hell)
    代码中有大量异步逻辑,并且出现大量异步任务依赖其它异步任务的结果时,必然会出现回调中套回调情况。我们需要使用async/await和Future.then来解决这种问题。
    使用场景:大量依赖的业务逻辑,登录流程逻辑等
    先来看下回调地狱例子:
//先分别定义各个异步任务
Future<String> future1(String str1){...
//第一个任务
};
Future<String> future2(String str2){...
//第二个任务
};
Future future3(String info){...// 第三个任务
};future1("str1").then((str2){//1返回数据,作为2的参数future2(str2).then((info){//2的返回数据,作为3的入参future3(info).then((){//获取3的返回数据...});});
})

Future消除Callback Hell
使用Future的链式机制,依次向下就避免了嵌套。跟JS的Promise完全一样。不足之处是还是有一层回调。

future1("str1").then((str2){return future2(str2);
}).then((info){return future3(info);
}).then((e){//执行3接下来的操作 
}).catchError((e){//错误处理  print(e);
});

async/await消除callback hell
上边的方式虽然避免了嵌套,但是在每个方法还是有一层回调。我们可以使用async/await来实现像同步代码那样来执行异步任务而不使用回调的方式。

task() async {try{String str2 = await future1("str1");String info = await future2(str2);await future3(info);//执行接下来的操作   } catch(e){//错误处理   print(e);   }  
}
  • async/await
    async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用then方法添加回调函数

await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。

async/await将一个异步流用同步的代码表现出来。

async/await只是一个语法糖,JS编译器或Dart解释器最终都会将其转化为一个JS的Promise和Dart的Future的调用链。

Stream

如果说Future是可以接收单个异步事件返回单个事件的成功失败,那么Stream就可以接收多个异步事件,并返回多个事件的成功失败,供使用者使用。
使用场景:多次读取数据的异步任务场景,如网络内容下载、文件读写等
该例子借助了其他地方的例子。

Stream.fromFutures([// 1秒后返回结果Future.delayed(new Duration(seconds: 1), () {return "hello 1";}),// 抛出一个异常Future.delayed(new Duration(seconds: 2),(){throw AssertionError("Error");}),// 3秒后返回结果Future.delayed(new Duration(seconds: 3), () {return "hello 3";})
]).listen((data){print(data);
}, onError: (e){print(e.message);
},onDone: (){});

控制台输出

flutter: hello 1
flutter: Error
flutter: hello 3

Future.wait是函数中存在多个延时操作,则以延时最长操作完成后统一返回,其他的延时操作等待最长的延时操作完成。

async/await:处理多个异步操作,前后有依赖逻辑的,使用异步实现同步。

Stream:统一监听该Stream中的多个异步延时操作返回,相当于之前的多个Future异步处理统一监听。

  • 其中Future和Stream只做了常用的方法和函数的介绍,更详细的会在之后依次给大家做下总结。

到这里大概把Dart中经常使用的语法和属性方法介绍了一遍,有错误或者理解不到位的地方,可以提出,共同进步。

Dart相比Java和JavaScript还是有许多优点有优势的,Dart既能进行服务端脚本、APP开发、web开发,但是生态目前不足,不过Flutter目前火热,相信生态之后会越来越好。

这篇关于Flutter Dart语法学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997734

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件