Flutter基础 -- Dart 语言 -- 进阶使用

news2024/11/13 9:36:41

目录

1. 泛型 generics

1.1 泛型使用

1.2 泛型函数

1.3 构造函数泛型

1.4 泛型限制

2. 异步 async

2.1 异步回调 then

2.2 异步等待 await

2.3 异步返回值

3. 生成器 generate (了解)

3.1 同步生成器 sync*

使用 sync* 的场景

总结

3.2 异步生成器 async*

使用 StreamSubscription 的优势

3.3 递归生成器 sync*

4. 类型定义 typedef

4.1 typedef 定义使用

4.2 简化常用类型定义

5. 空安全

5.1 默认不可空

5.2 type? 可空

5.3 value! 值保证不为空,主观上

5.4 value?. 不为空才执行

5.5 value?? 如果空执行

5.6 late 声明

5.7 late 类成员延迟初始

5.8 List、泛型

5.9 Map

6. 扩展 extension

6.1 示例 扩展日期时间

6.2 业务场景


1. 泛型 generics

1.1 泛型使用

main(List<String> args) {
  var l = <String>[];
  l.add('aaa');
  l.add('bbb');
  l.add('ccc');
  print(l);

  var m = <int, String>{};
  m[1] = 'aaaa';
  m[2] = 'bbbb';
  m[3] = 'cccc';
  print(m);
}

[aaa, bbb, ccc]
{1: aaaa, 2: bbbb, 3: cccc}

容器对象,在创建对象时都可以定义泛型类型

1.2 泛型函数

K addCache<K, V>(K key, V val) {
  print('$key -> $val');
  return val;
}

main(List<String> args) {
  var key = addCache('url', 'https://wiki.doucafecat.tech');
  print(key);
}

url -> https://wiki.doucafecat.tech
https://wiki.doucafecat.tech

1.3 构造函数泛型

class Phone<T> {
  final T mobileNumber;
  Phone(this.mobileNumber);
}

main(List<String> args) {
  var p = Phone<String>('ducafecat');
  print(p.mobileNumber);
}

ducafecat

这是大多数情况下使用泛型的场景,在一个类的构造函数中(Phone是一个泛型类)

(就是cpp的template)

1.4 泛型限制

定义

class AndroidPhone {
  void startup() {
    print('Android Phone 开机');
  }
}

class Phone<T extends AndroidPhone> {
  final T mobile;
  Phone(this.mobile);
}

实例

main(List<String> args) {
  var ad = AndroidPhone();
  var p = Phone<AndroidPhone>(ad);
  p.mobile.startup();
}

Android Phone 开机

通过 extends 关键字 可以限定你可以泛型使用的类型

通过 class Phone<T extends AndroidPhone> {

就可以让传入的实参必须是 AndroidPhone类型 或者 是 AndroidPhone类型的子类

2. 异步 async

2.1 异步回调 then

import 'package:dio/dio.dart';

void main() {
  Dio dio = Dio();
  dio.get("https://wpapi.ducafecat.tech/products/categories").then((response) {
    print(response.data);
  });
}

[{id: 34, name: Bag, slug: bag, parent: 0, description: ...

then 的方式异步回调

在 Dart 中,then 方法用于处理返回了 Future 的异步操作。当 Future 完成时,then 方法所传入的回调函数会被执行

2.2 异步等待 await

import 'package:dio/dio.dart';

void main() async {
  Dio dio = Dio();
  Response<String> response =
      await dio.get("https://wpapi.ducafecat.tech/products/categories");
  print(response.data);
}

[{id: 34, name: Bag, slug: bag, parent: 0, description: ...

async 写在函数定义 await 写在异步请求头

在 Dart 中,async 和 await 关键字用于简化异步编程,使得代码逻辑和控制流更像是同步代码。 它们主要用于处理 Future 对象,从而让异步代码更加易读

  1. async 关键字
    • 当你在函数声明时使用 async 关键字时,表示这个函数是异步函数
    • async 函数总是返回一个 Future,即使你直接返回一个非 Future 类型的值(这种情况下这个值将会被自动包装成一个 Future
  2. await 关键字
    • await 关键字只能在 async 函数中使用,它用于等待一个返回 Future 的表达式完成,并获取其结果
    • 在 await 关键字之后的代码会暂停执行,直到 Future 完成,并将其结果赋值给左侧的变量
   Response<String> response =
      await dio.get("https://wpapi.ducafecat.tech/products/categories");

在这里,await 暂停了 main 函数的执行,直到 dio.get 异步操作完成,并将请求成功返回的响应赋值给 response 变量

2.3 异步返回值

import 'package:dio/dio.dart';

Future<String?> getUrl(String url) async {
  Dio dio = Dio();
  Response<String> response = await dio.get(url);
  return response.data;
}

void main() async {
  var content =
      await getUrl('https://wpapi.ducafecat.tech/products/categories');
  print(content);
}

[{id: 34, name: Bag, slug: bag, parent: 0, description: ...

定义 Future<T> 返回对象

代码展示了如何使用 Dart 中的 async 和 await 关键字来处理异步 HTTP 请求,并把请求操作提取到一个单独的函数里。这种方式不仅使代码更具有模块化,还能提高可读性和维护性

3. 生成器 generate (了解)

3.1 同步生成器 sync*

Iterable<int> naturalsTo(int n) sync* {
  print('start');
  int k = 0;
  while (k < n) {
    yield k++;
  }
  print('end');
}

main(List<String> args) {
  var it = naturalsTo(5).iterator;
  while (it.moveNext()) {
    print(it.current);
  }
}

start
0
1
2
3
4
end

yield 会等待 moveNext 指令

使用 sync* 的场景

延迟计算: 生成器可以在需要时生成元素,而不是一次性生成所有元素

内存效率: 适用于处理大量或无限数据流,因为它们逐个生成元素,而不需要一次性加载到内存中

流控制: 可以在生成元素之间执行其他逻辑,如打印日志、计算等

总结

sync* 关键字用于定义一个同步生成器函数,yield 则用于逐个生成元素。生成器函数非常适合处理需要延迟计算、大量数据或无限数据流的场景。它们提高了内存效率,同时保持代码简洁和易读

3.2 异步生成器 async*

import 'dart:async';

Stream<int> asynchronousNaturalsTo(int n) async* {
  print('start');
  int k = 0;
  while (k < n) {
    yield k++;
  }
  print('end');
}

main(List<String> args) {
  // 流监听
  // asynchronousNaturalsTo(5).listen((onData) {
  //   print(onData);
  // });

  // 流监听 StreamSubscription 对象
  StreamSubscription subscription = asynchronousNaturalsTo(5).listen(null);
  subscription.onData((value) {
    print(value);
    // subscription.pause();
  });
}

start
0
1
2
3
4
end

以流的方式一次性推送

StreamSubscription 对象进行流监听控制

使用 StreamSubscription 的优势

流控制StreamSubscription 对象允许你控制流的行为,比如暂停 (pause) 和恢复 (resume) 流

取消订阅: 你可以通过 subscription.cancel() 方法取消订阅流,避免资源浪费

监听错误和完成: 可以使用 subscription.onError 和 subscription.onDone 方法分别处理错误和流完成事件

3.3 递归生成器 sync*

Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}

main(List<String> args) {
  var it = naturalsDownFrom(5).iterator;
  while (it.moveNext()) {
    print(it.current);
  }
}

5
4
3
2
1

yield* 以指针的方式传递递归对象,而不是整个同步对象

4. 类型定义 typedef

4.1 typedef 定义使用

采用 typedef

typedef MyPrint = void Function(String val);

class PrintClass {
  MyPrint print;
  PrintClass(this.print);
}

main() {
  PrintClass coll = PrintClass((String val) => print(val));
  coll.print('hello world');
}

hello world

未采用 typedef

class PrintClass {
  void Function(String val) print;
  PrintClass(this.print);
}

main() {
  PrintClass coll = PrintClass((String val) => print(val));
  coll.print('hello world');
}

hello world

4.2 简化常用类型定义

定义

typedef MapStringAny = Map<String, dynamic>;
typedef MapAnyString = Map<dynamic, String>;
typedef MapStringString = Map<String, String>;
typedef MapStringDouble = Map<String, double>;
typedef MapDoubleString = Map<double, String>;
typedef MapDoubleDouble = Map<double, double>;
typedef MapIntInt = Map<int, int>;
typedef MapIntDouble = Map<int, double>;

typedef ListString = List<String>;
typedef ListInt = List<int>;
typedef ListDouble = List<double>;
typedef ListAny = List<dynamic>;

使用

main() {
  ListString p = [];
  p.add('a');
  p.add('b');
  p.add('c');

  MapStringAny m = {};
  m['a'] = 1;
  m['b'] = 2;
  m['c'] = 3;
}

5. 空安全

5.1 默认不可空

String title = 'ducafecat';

5.2 type? 可空

String? title = null;

5.3 value! 值保证不为空,主观上

String? title = 'ducafecat';
String newTitle = title!;

就是骗一骗编译器

5.4 value?. 不为空才执行

String? title = 'ducafecat';
bool isEmpty = title?.isEmpty();

5.5 value?? 如果空执行

String? title = 'ducafecat';
String newTitle = title ?? 'cat';

像构里面就挺好用的

5.6 late 声明

延迟加载修饰符

声明一个不可空的变量,并在声明后初始化

late String description;

void main() {
  description = 'Feijoada!';
  print(description);
}

本来要在声明的时候初始化的,加上 late 就告诉编译器我们后面再初始化

5.7 late 类成员延迟初始

class WPHttpService extends GetxService {
  late final Dio _dio;

  @override
  void onInit() {
    ...

    _dio = Dio(options);

    ...
  }

加上 late 后就可以不用构造函数的时候初始化了

5.8 List、泛型

  List<String?>? l;
  l = [];
  l.add(null);
  l.add('a');
  print(l);

5.9 Map

  Map<String, String?>? m;
  m = {};
  m['a'] = 'b';
  m['b'] = null;
  print(m);

* 可能返回空

6. 扩展 extension

extension 本质上还是和继承一样扩展了方法

但这是一种简洁优雅的方式,你可以想想之前继承的繁琐

6.1 示例 扩展日期时间

加入依赖包 pubspec.yaml

dependencies:
  intl: ^0.17.0

编写扩展类 ExDateTime

import 'package:intl/intl.dart';

extension ExDateTime on DateTime {
  /// 方法,格式化日期 yyyy-MM-dd
  String toDateString({String format = 'yyyy-MM-dd'}) =>
      DateFormat(format).format(this);

  // 属性
  int get nowTicket => this.microsecondsSinceEpoch;
}

main() {
  var now = DateTime.now();

  print(now.toDateString());
  print(now.nowTicket);
}

我们给可以扩展类加个前缀 Ex 这样一看就知道是扩展

6.2 业务场景

功能函数

视图组件

创作不易,希望读者三连支持 💖
赠人玫瑰,手有余香 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1807523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件项目调研三部曲(调研计划,调研大纲,调研报告)原件获取

软件项目详细调研的目的是依据项目合同的要求&#xff0c;能够通过在客户现场&#xff0c;并通过访谈的方式&#xff0c;尽可能的了解客户的需求和业务现状&#xff0c;包括客户涉及到的业务部门的岗位设置、岗位职责、工作内容、工作流程、管理难点以及通过实施信息化系统的期…

Silanna UV光荣推出了一款革命性的高功率远紫外线LED

这款令人瞩目的光源&#xff0c;拥有令人震撼的235nm波长&#xff0c;并被巧妙地封装在紧凑的6.8mm结构中&#xff0c;其魅力与实力兼具。 今年六月&#xff0c;在苏格兰圣安德鲁斯大学举行的盛大2024年远紫外科学和技术国际大会&#xff08;ICFUST&#xff09;上&#xff0c;S…

深度剖析AI机会,数字人智能对话系统:未来的人机交互新范式

Datawhale干货 作者&#xff1a;邓恺俊&#xff0c;Datawhale成员 随着人工智能时代的到来&#xff0c;大模型的技术日新月异&#xff0c;我们不仅仅满足于文字之间的交互&#xff0c;希望能够有更近一步的交流。既然现在文字已经能够很好的模拟人类了&#xff0c;那随之而来的…

牛客网刷题 | BC120 争夺前五名

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 期中考试开始了&am…

基于非下采样小波包分析的滚动轴承故障诊断(MATLAB R2021B)

小波变换具有良好的时频局部化特性和多分辨率特性&#xff0c;可准确定位信号的突变点并可在不同尺度上描述信号的局部细节特征&#xff0c;被广泛应用于信号降噪。但标准正交小波变换不具有平移不变性&#xff0c;采用标准正交小波对信号消噪后&#xff0c;会在脉冲尖峰处产生…

Dubbo 3.x源码(21)—Dubbo服务引用源码(4)

基于Dubbo 3.1&#xff0c;详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了createInvokerForRemote方法中的Wrapper有哪些以及作用&#xff0c;接下来我们将会的学习真正的本地、应用级别、接口级别的Protocol的引入逻辑&#xff0c;以及创建Proxy服务接口代理对象的逻…

UI学习的案例——照片墙

照片墙案例 在实现照片墙案例之前先讲一下userInteractionEnable这个属性。 首先这个属性属于UIView&#xff0c;这个属性是bool类型&#xff0c;如果为YES的话&#xff0c;这个UIView会接受有关touch和keyboard的相关操作&#xff0c;然后UIView就可以通过相应的一些方法来处…

Hive日志介绍

日志描述 日志路径&#xff1a;Hive相关日志的默认存储路径为“/var/log/Bigdata/hive/角色名”&#xff0c;Hive1相关日志的默认存储路径为“/var/log/Bigdata/hive1/角色名”&#xff0c;以此类推。 HiveServer&#xff1a;“/var/log/Bigdata/hive/hiveserver”&#xff0…

# log.info(“消息发送成功“); 红色报错 解决方案

log.info(“消息发送成功”); 红色报错 解决方案 一、错误描述&#xff1a; 在使用 idea 创建 maven 项目导入 lombok 依赖时&#xff0c;出现 log.info 报红错误&#xff0c;检查导入依赖正确&#xff0c;网络正常&#xff0c;错误依旧。 二、解决方案&#xff1a; 1、在 i…

MATLAB入门知识

目录 原教程链接&#xff1a;数学建模清风老师《MATLAB教程新手入门篇》https://www.bilibili.com/video/BV1dN4y1Q7Kt/ 前言 历史记录 脚本文件&#xff08;.m&#xff09; Matlab帮助系统 注释 ans pi inf无穷大 -inf负无穷大 i j虚数单位 eps浮点相对精度 0/&a…

架构设计-加密解决的基本工具方法

软件工程实施过程中&#xff0c;经常会用到加密解密相关的工具类&#xff0c;整理如下&#xff1a; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;import javax.crypto.Cipher; import java.security.*; import java.security.interfaces.RSAPrivateKey; imp…

利用CSS隐藏HTML元素并插入替代内容

在创建一个支持切换阅读模式和答题模式的Anki问答题模板中&#xff0c;我创建了一个支持切换阅读模式和答题模式的问答题模板&#xff0c;该文最终利用JavaScript将Anki输出的向下箭头删除&#xff0c;并插入自定义的提示语。经过进一步测试&#xff0c;发现实现上述功能完全不…

一步一学!如何通过SOLIDWORKS曲面放样绘制花瓶?

SOLIDWORKS中&#xff0c;我们对放样凸台的操作已经非常熟悉。现在&#xff0c;我们将进一步探索曲面菜单栏中的放样成型功能。 1、绘制草图 首先&#xff0c;同普通放样凸台建模相同&#xff0c;绘制放样轮廓及引导线段。 可通过创建基准面布置轮廓&#xff0c;利用穿透选项将…

定个小目标之刷LeetCode热题(13)

今天来看看这道题&#xff0c;介绍两种解法 第一种动态规划&#xff0c;代码如下 class Solution {public int maxSubArray(int[] nums) {int pre 0, maxAns nums[0];for (int x : nums) {// 计算当前最大前缀和pre Math.max(pre x, x);// 更新最大前缀和maxAns Math.ma…

第一百零二节 Java面向对象设计 - Java静态内部类

Java面向对象设计 - Java静态内部类 静态成员类不是内部类 在另一个类的主体中定义的成员类可以声明为静态。 例子 以下代码声明了顶级类A和静态成员类B&#xff1a; class A {// Static member classpublic static class B {// Body for class B goes here} }注意 静态成…

python实现将excel数据指保存到word表格中

准备一个excel表格 上代码&#xff1a; import openpyxl from docx import Document# 读取Excel文件 excel_file 大学名次.xlsx wb openpyxl.load_workbook(excel_file) ws wb.active# 获取Excel文件中的所有工作表名称 sheet_names wb.sheetnames# 遍历每个工作表&#x…

每日题库:Huawe数通HCIA——15(30道)

注&#xff1a;由于限制原因&#xff0c;今后资料仅提供给粉丝 所有资料均来源自网络&#xff0c;但个人亲测有效&#xff0c;特来分享&#xff0c;希望各位能拿到好成绩&#xff01; PS&#xff1a;别忘了一件三连哈&#xff01; 今日题库&#xff1a; 231. 如下图所示的网…

【机器学习】Qwen2大模型原理、训练及推理部署实战

目录​​​​​​​ 一、引言 二、模型简介 2.1 Qwen2 模型概述 2.2 Qwen2 模型架构 三、训练与推理 3.1 Qwen2 模型训练 3.2 Qwen2 模型推理 四、总结 一、引言 刚刚写完【机器学习】Qwen1.5-14B-Chat大模型训练与推理实战 &#xff0c;阿里Qwen就推出了Qwen2&#x…

《大道平渊》· 拾壹 —— 商业一定是个故事:讲好故事,员工奋发,顾客买单。

《大道平渊》 拾壹 "大家都在喝&#xff0c;你喝不喝&#xff1f;" 商业一定是个故事&#xff0c;人民群众需要故事。 比如可口可乐的各种故事。 可口可乐公司也只是被营销大师们&#xff0c; 作为一种故事载体&#xff0c;发挥他们的本领。 营销大师们开发故事…

解锁ChatGPT:从GPT-2实践入手解密ChatGPT

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…