当前位置: 首页 > news >正文

网站图标 代码微信开发网站建设程序

网站图标 代码,微信开发网站建设程序,西安seo外包工作室,36kr wordpress参考自《flutter实战》 变量声明 var Dart 中 var 变量一旦赋值,类型便会确定(会自动推断一个类型),则不能再改变其类型 void main() {var name Bob;print(name); // Bob }如果把他重新赋值 123, 会报错 void main() {var name …

参考自《flutter实战》

变量声明

var

Dart 中 var 变量一旦赋值,类型便会确定(会自动推断一个类型),则不能再改变其类型

void main() {var name = 'Bob';print(name); // Bob
}

如果把他重新赋值 123, 会报错

void main() {var name = 'Bob';name = 123; // A value of type 'int' can't be assigned to a variable of type 'String'.print(name);
}

dynamic和Object

Object 是 Dart 所有对象的根基类,也就是说在 Dart 中所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象。 dynamicObject声明的变量都可以赋值任意对象,且后期可以改变赋值的类型

void main() {dynamic t;Object x;t = "hi world";x = 'Hello Object';// 可以重新赋值给另外的变量t = 1000;x = 1000;print("$t $x"); // 1000 1000
}

dynamicObject不同的是dynamic声明的对象编译器会提供所有可能的组合,而Object声明的对象只能使用 Object 的属性与方法, 否则编译器会报错,如

dynamic a;
Object b = "";
void main() {a = "";printLengths();
}   printLengths() {// 正常print(a.length);// 报错 The getter 'length' isn't defined for the type 'Object'.print(b.length);// a是字符串,没有"xx"属性,编译时不会报错,运行时会报错print(a.xx);
}

dynamic 的这个特点使得我们在使用它时需要格外注意,这很容易引入一个运行时错误,比如下面代码在编译时不会报错,而在运行时会报错:

print(a.xx);

final(终值)和const(常量)

如果你不打算更改一个变量,可以使用 finalconst 修饰它,而不是使用 var 或作为类型附加。一个 final 变量只能设置一次,const 变量是编译时常量。(const 常量隐式包含了 final。)

final

final会自动推导变量的类型,final变量的值不能再次修改

void main() {final name = 'Bob'; // 会自动推导类型final String nickname = 'Bobby';print("$name $nickname"); // Bob Bobby// 不能改变final变量的值 The final variable 'name' can only be set once.name = 'Alice';
}
const

一般使用const定义常量, const也会自动推导类型

void main() {const bar = 1000000;const double atm = 1.01325 * bar;print("$atm"); // 1013250.0
}   

const 关键字不仅仅可用于声明常量,你还可以使用它来创建常量 值(values) ,以及声明 创建(create) 常量值的构造函数。任何变量都可以拥有常量值。

void main() {var foo = const [];final bar = const [];const baz = []; // 等同于 `const []`print("$foo $baz $baz"); // [] [] []
}   

如果一个变量没被声明为 final 或者 const,那么,即使它的值是 const,你仍然可以修改这个变量,如下:

void main() {var foo = const [];final bar = const [];const baz = []; // 等同于 `const []`print("$foo $bar $baz"); // [] [] []foo = [1, 2, 3];print("$foo $baz $baz"); // [1, 2, 3] [] []
}

但是这里bar和baz的值不能再变化

void main() {var foo = const [];final bar = const [];const baz = []; // 等同于 `const []`print("$foo $bar $baz"); // [] [] []foo = [1, 2, 3];// The final variable 'bar' can only be set once.bar = [1];// Constant variables can't be assigned a value.baz = [1, 2, 3];print("$foo $baz $baz"); // [1, 2, 3] [] []
}   

可以在定义常量时使用 类型检查和转换(isas)、 集合中的if 和 展开操作符(...

void main() {
const Object i = 3;
const list = [i as int];
const map = {if (i is int) i: 'int'};
const set = {if (list is List<int>) ...list};
print("$map $set"); // {3: int} {3}
}
空安全

定义变量时我们可以指定变量是可空还是不可空。对于可空变量,我们在使用前必须判空。如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错。

void main() {int i = 8;int? j;late int k;k=9;
}   

如果一个变量我们定义为可空类型,在某些情况下即使我们给它赋值过了,但是预处理器仍然有可能识别不出,这时我们就要显式(通过在变量后面加一个”!“符号)告诉预处理器它已经不是null了

class Test{int? i;Function? fun;say(){if(i!=null) {print(i! * 8); //因为已经判过空,所以能走到这 i 必不为null,如果没有显式申明,则 IDE 会报错}if(fun!=null){fun!(); // 同上}}
}

如果函数变量可空时,调用的时候可以用语法糖

fun?.call() // fun 不为空时则会被调用

函数

函数声明

bool isNoble(int atomicNumber) {return _nobleGases[atomicNumber] != null;
}

Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理,函数返回值没有类型推断

// 一个无参数且返回 bool类型的函数
typedef bool CALLBACK();Map<dynamic, dynamic> _nobleGases = {};//不指定返回类型,此时默认为dynamic,不是bool
isNoble(int atomicNumber) {return _nobleGases[atomicNumber] != null;
}void test(CALLBACK cb){print(cb()); 
}void main() {// 报错,isNoble不是bool类型test(isNoble);
}   

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

bool isNoble(int atomicNumber) => true;  

做为变量

var say = (str){print(str);
};void main() {say("hello world"); // hello world
}

作为参数传递

void execute(var callback) {callback(); //执行传入的函数
}
void main() {execute(() => print("xxx")); // xxx
}
可选的位置参数

包装一组函数参数,用[]标记为可选的位置参数,并放在参数列表的最后面

void say(String from, String msg, [String? device]) {var result = '$from says $msg';if (device != null) {result = '$result with a $device';}print(result);
}void main() {say('Bob', 'Howdy'); // Bob says Howdysay('Bob', 'Howdy', 'smoke signal'); // Bob says Howdy with a smoke signal
}
可选的命名参数

定义函数时,使用{param1, param2, …},放在参数列表的最后面,用于指定命名参数

void enableFlags({required bool bold, required bool hidden}) {print("$bold $hidden");
}void main() {enableFlags(bold: true, hidden: false); // true false
}

mixin

Dart 是不支持多继承的,但是它支持 mixin。下面的例子,定义了几个 mixin,然后通过 with 关键字将它们组合成不同的类。有一点需要注意:如果多个mixin 中有同名方法,with 时,会默认使用最后面的 mixin 的,mixin 方法中可以通过 super 关键字调用之前 mixin 或类中的方法。

class Person {say() {print('say');}
}mixin Eat {eat() {print('eat');}
}mixin Walk {walk() {print('walk');}
}mixin Code {code() {print('key');}
}class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}void main() {Dog dog = Dog();dog.eat();  // 输出: eatdog.walk(); // 输出: walkMan man = Man();man.say();  // 输出: sayman.eat();  // 输出: eatman.walk(); // 输出: walkman.code(); // 输出: key
}

异步

Future

与JavaScript中的Promise非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果,要么成功,要么失败。

then

使用Future.delayed 创建了一个延时任务(实际场景会是一个真正的耗时任务,比如一次网络请求),即2秒后返回结果字符串"hello world!",然后我们在then中接收异步结果并打印结果

void main() {Future.delayed(Duration(seconds: 2),(){return "hello world!";}).then((data){print(data); // hello world!});
}
catchError

如果异步任务发生错误,可以在catchError中捕获错误

void main() {Future.delayed(Duration(seconds: 2),(){throw AssertionError("Error");  }).then((data){//执行成功会走到这里  print("success");}).catchError((e){//执行失败会走到这里  // Assertion failed: "Error"print(e);});
}

并不是只有 catchError回调才能捕获错误,then方法还有一个可选参数onError,也可以用它来捕获异常

void main() {Future.delayed(Duration(seconds: 2), () {//return "hi world!";throw AssertionError("Error");}).then((data) {print("success");}, onError: (e) {// Assertion failed: "Error"print(e);});
}
whenComplete

有些时候,我们会遇到无论异步任务执行成功或失败都需要做一些事的场景,比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。这种场景,有两种方法,第一种是分别在thencatch中关闭一下对话框,第二种就是使用FuturewhenComplete回调

void main() {Future.delayed(Duration(seconds: 2),(){throw AssertionError("Error");}).then((data){//执行成功会走到这里 print(data);}).catchError((e){//执行失败会走到这里   print(e);}).whenComplete((){//无论成功或失败都会走到这里// 先打印错误信息,后打印“结束”print('结束');});
}
wait

有些时候,我们需要等待多个异步任务都执行结束后才进行一些操作,比如我们有一个界面,需要先分别从两个网络接口获取数据,获取成功后,我们需要将两个接口数据进行特定的处理后再显示到UI界面上,应该怎么做?答案是Future.wait,它接受一个Future数组参数,只有数组中所有Future都执行成功后,才会触发then的成功回调,只要有一个Future执行失败,就会触发错误回调。下面,我们通过模拟Future.delayed 来模拟两个数据获取的异步任务,等两个异步任务都执行成功时,将两个异步任务的结果拼接打印出来。效果类似js的promise.all

void main() {Future.wait([// 2秒后返回结果  Future.delayed(Duration(seconds: 2), () {return "hello";}),// 4秒后返回结果  Future.delayed(Duration(seconds: 4), () {return " world";})]).then((results){// 4秒后 hello worldprint(results[0]+results[1]);}).catchError((e){print(e);});
}

async/await

回调地狱

如果代码中有大量异步逻辑,并且出现大量异步任务依赖其他异步任务的结果时,必然会出现Future.then回调中套回调情况。举个例子,比如现在有个需求场景是用户先登录,登录成功后会获得用户ID,然后通过用户ID,再去请求用户个人信息,获取到用户个人信息后,为了使用方便,我们需要将其缓存在本地文件系统

// 登录
Future<String> login(String userName, String pwd){String result = "$userName $pwd idGet";return Future.delayed(Duration(seconds: 2), () {return result;});
}// 获取信息
Future<String> getUserInfo(String id){String result = "$id infoGet";return Future.delayed(Duration(seconds: 2), () {return result;});
}// 保存信息
Future saveUserInfo(String userInfo){String result = "$userInfo save!";return Future.delayed(Duration(seconds: 2), () {return result;});
}void main() {// 登录login("alice","******").then((id){// 获取信息getUserInfo(id).then((userInfo){// 保存信息saveUserInfo(userInfo).then((res){// 6秒后打印 alice ****** idGet infoGet save!print(res);});});});
}
消除回调地狱
Future

Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用” ,如果在then 中返回的是一个Future的话,该future会执行,执行结束后会触发后面的then回调,这样依次向下,就避免了层层嵌套。

void main() {login("alice","******").then((id){return getUserInfo(id);}).then((userInfo){return saveUserInfo(userInfo);}).then((res){// 6秒后打印 alice ****** idGet infoGet save!print(res);}).catchError((e){//错误处理  print(e);});
}
async/await

通过Future回调中再返回Future的方式虽然能避免层层嵌套,但是还是有一层回调,有没有一种方式能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式?答案是肯定的,这就要使用async/await

task() async {try{String id = await login("alice","******");String userInfo = await getUserInfo(id);String res = await saveUserInfo(userInfo);// 6秒后打印 alice ****** idGet infoGet save!  print(res);} catch(e){//错误处理   print(e);   }  
}
void main() {task();
}

数据流

Stream 也是用于接收异步事件数据,和 Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。

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

输出

hello 1
Error
hello 3

期待你的关注

在这里插入图片描述

http://www.dtcms.com/a/512408.html

相关文章:

  • 修改 Docker 容器中 MySQL 8.0 默认编码为 utf8mb4_unicode_ci
  • C# Dictionary 线程安全指南:多线程下操作 Dictionary<string, DateTime> 的加锁策略
  • 企业im聊天软件支持什么功能,应该怎么选?
  • 【Linux系统编程】权限的概念
  • githup网站建设网站营销站点有你想
  • 差分|递归
  • 如何通过纺织服装MES系统提升生产效率和管理水平?
  • 打通智慧高速核心系统:湖南某新建项目的收费、通信、监控一体化实践
  • 河南网站建设优化技术福建省建设干部网站
  • 智能机器人:今年双十一“减人增效”的AI智能客服机器人方案
  • 市环保局网站建设方案建站公司哪家好 知道万维科技
  • 房产中介网站建设的目的cms 美容网站 模版
  • vue开发中,如果出现了反显数据有问题(后端明明返回的有数据,但就是不反显,没有值)是什么原因
  • 【2025-系统规划与管理师】第12章:信息系统服务管理
  • C++---嵌套类型(Nested Types)封装与泛型的基石
  • Floyd判圈算法(Floyd Cycle Detection Algorithm)
  • 网站建设支付宝温州建设学校网站
  • 深圳网站制作 优选灵点网络前端开发语言有哪些
  • .NET8 通过自定义类映射appsettings.json 文件某个节点的配置
  • 25-DAPO: An Open-Source LLM Reinforcement LearningSystem at Scale
  • 6个网站建设网站设置保存登录密码怎么取消
  • 网站建设和维护的职责网站开发工程师有证书考试吗
  • 网站建设计算机人员招聘策划营销方案
  • 《i.MX6ULL LED 驱动实战:内核模块开发与 GPIO 控制》
  • Effective Java学习笔记:用静态工厂方法代替构造器(第一条)
  • TDengine 数学函数 POW 用户手册
  • AI大模型“战国策”:主流LLM平台简单介绍
  • Prometheus监控部署——pushgateway自动推送
  • 网站布局优化问问建设网站的人
  • 做网站宜宾深圳龙华网站建设公司