【Flutter从入门到入坑之二】Dart语言基础概述

官方文档:https://api.dart.cn/stable/2.16.2/dart-core/dart-core-library.html

关于新技术的学习,一直以来我都非常认同一个观点:千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样才能从高维度理解问题。 所以,为了我们更高效地掌握 Dart,以最快的速度具备开发一款 Flutter 应用的能力,这里,我会先从 Flutter 开发的角度,介绍 Dart 语言的基础知识。


我们在学习 Dart 基础知识之前,我们先来了解一下 Dart 的由来以及 Dart 的特性。

Dart 概述

Dart 是什么?

2011年10月,在 GOTO 大会上,Google 发布了一种新的编程语言 Dart。Dart 的诞生正是要解决 JavaScript 存在的、在语言本质上无法改进的缺陷。出于对 JavaScript 的不满,Google 的程序员们决定自己写一个新语言来换掉它,所以 Dart 的最初定位也是一种运行在浏览器中的脚本语言。为了推广 Dart,Google 甚至将自己的 Chrome 浏览器内置了 Dart VM,可以直接高效地运行 Dart 代码。
由于缺少顶级项目的使用,Dart 始终不温不火。2015 年,在听取了大量开发者的反馈后,Google 决定将内置的 Dart VM 引擎从 Chrome 移除,这对 Dart 的发展来说是重大挫折,替代 JavaScript 就更无从谈起了。
Dart 也借此机会开始转型:在 Google 内部孵化了移动开发框架 Flutter,弯道超车进入了移动开发的领域。Dart 也成为专注大前端与跨平台生态的语言。

Dart 的特性

  • JIT 与 AOT
    Dart 是少数同时支持 JIT(Just In Time,即时编译)和 AOT(Ahead of Time,运行前编译)的语言之一。
    语言在运行之前通常都需要编译,JIT 和 AOT 则是最常见的两种编译模式。

    • JIT 在运行时即时编译,在开发周期中使用,可以动态下发和执行代码,开发测试效率高,但运行速度和执行性能则会因为运行时即时编译受到影响。
    • AOT 即提前编译,可以生成被直接执行的二进制代码,运行速度快、执行性能表现好,但每次执行前都需要提前编译,开发测试效率低。

    总结来讲,在开发期使用 JIT 编译,可以缩短产品的开发周期。Flutter 最受欢迎的功能之一热重载,正是基于此特性。而在发布期使用 AOT,就不需要像 React Native 那样在跨平台 JavaScript 代码和原生 Android、iOS 代码之间建立低效的方法调用映射关系。所以说,Dart 具有运行速度快、执行性能好的特点。

  • 内存分配与垃圾回收
    Dart VM 的内存分配策略比较简单,创建对象时只需要在堆上移动指针,内存增长始终是线性的,省去了查找可用内存的过程。
    在 Dart 中,并发是通过 Isolate 实现的。Isolate 是类似于线程但不共享内存,独立运行的 worker。这样的机制,就可以让 Dart 实现无锁的快速分配。

    Dart 的垃圾回收,则是采用了多生代算法。新生代在回收内存时采用“半空间”机制,触发垃圾回收时,Dart 会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存。回收过程中,Dart 只需要操作少量的“活跃”对象,没有引用的大量“死亡”对象则被忽略,这样的回收机制很适合 Flutter 框架中大量 Widget 销毁重建的场景。

  • 单线程模型
    Dart 中并没有线程,只有 Isolate(隔离区)。Isolates 之间不会共享内存,就像几个运行在不同进程中的 worker,通过事件循环(Event Looper)在事件队列(Event Queue)上传递消息通信。

  • 无需单独的声明式布局语言
    Dart 声明式编程布局易于阅读和可视化,使得 Flutter 并不需要类似 JSX 或 XML 的声明式布局语言。所有的布局都使用同一种格式,也使得 Flutter 很容易提供高级工具使布局更简单。


一、基本语法

  1. 主函数(入口函数)

    void main(List<String> arguments) {
    	print('Hello world! ${arguments}');
    }
    
  2. 基本类型

    // 基本类型
    // int
    int age = 20;
    // double
    double count = 10.0;
    // String
    String 
    // bool
    bool flag = true;
    // List
    List list = [1,2,3,4,5,6];
    // Set
    Set set = new Set();
    set.addAll(list);
    // Map
    Map user = {'name': 'bajie', 'age': 18};
    // 类型可推导
    => var user = {'name': 'bajie', 'age': 18};
    print("${user['name']}")
    null
    // 常量
    const
    final
    /*
    * 区别:
    * const 必须先赋初值
    * final 可以后面赋值一次
    */ 
    // 变量
    var
    
  3. 函数

    // 1,函数创建
    // 2,函数传值
    // 3. 可选参数
    printName(String name, int age, [String sex = '男']) {
    	print("name is ${name}, age is ${age}, sex is ${sex}")
    }
    // 4. 命名函数
    printName1({name, age=18, sex}) {
    	print("name is ${name}, age is ${age}, sex is ${sex}")
    }
    void main(List<String> arguments) {
    	printName('八戒', 18);
    	printName1({name: '八戒', age: 20, sex: '男'});
    }	
    

二、面向对象

  1. 类的封装

    /*
    * _ 标识私有属性
    */
    // 创建一个类
    // lib/animal.dart
    class Animal {
    	String? name;
    	Animal() {};
    	Animal.initFromName({ this.name });
    	void eat() {
    		print('${name} is eating!')
    	}
    } 
    
    // main.dart
    void main() {
    	Animal a = Animal.initFromName(name: 'bajie')
    	a.eat();
    }
    
  2. 类的继承

    // 继承一个类
    // lib/cat.dart
    class Cat {
    	// : => 在执行这个构造方法之前,先执行的操作
    	Cat.initFromName({ required String?name }) : super.initFromName(name: name);
    } 
    
    void main() {
    	Animal a = Animal.initFromName(name: 'bajie');
    	a.eat();
    	// 继承
    	// 在继承时,子类没有继承parent的命名构造函数
    	Cat c = Cat.initFromName(name: 'Tom');
    	c.eat();
    }
    
  3. 多态

    // lib/cat.dart
    class Cat {
    	// : => 在执行这个构造方法之前,先执行的操作
    	Cat.initFromName({ required String?name }) : super.initFromName(name: name);
    	// 重写一个方法
    	void eat() {
    		print('miaomiao~')
    	}
    } 
    
    void main() {
    	Animal a = Animal.initFromName(name: 'bajie');
    	a.eat();
    	// 多态
    	Animal c = Cat.initFromName(name: 'Tom');
    	c.eat();
    }
    

三、空安全 Null safety

1. 为什么需要空安全?
1.1 什么是空安全?
1.2 服务端——客户端
1.3 运行时——编译时
1.4 目标:对于空安全而言,我们的目标是让您对代码中的 null 可见且可控,并且确保它不会传递至某些位置从而引发崩溃。

在这里插入图片描述
在这里插入图片描述

  1. 怎么做的空安全 String? str;
    String? 就是 String|Null
    在这里插入图片描述
    我们将类型世界划分为了非空可空的两半。为了保持代码的健全和我们的原则:“除非您需要,否则您永远不会在运行时遇到空引用错误”,我们需要保证 null 不会出现在非空一侧的任何类型里。

看下面代码. 它将在调用 .length 时抛出 NoSuchMethodError 异常。null 值是 Null 类的一个实例,而 Null 没有 "length" getter

// Without null safety:
bool isEmpty(String string) => string.length == 0;
main() {
  isEmpty(null);
}

?!late

// In null-safe Dart, none of these can ever be null.var i = 42; // Inferred to be an int.String name = getFileName();final b = Foo();
var i = 42; 
String name = getFileName();
final b = Foo();
  • 如果这些变量 可以 为空值 ( null ), 在类型声明处 加上 ?

    int? aNullableInt = null;
    
  • 在您已经明确一个非空变量一定会在使用前初始化, 而 Dart 分析器仍然无法明确的情况下, 您可以在变量的类型前 加上 late

    class IntProvider {
      late int aRealInt;
      IntProvider() {
        aRealInt = calculate();
      }
    }
    
  • 当您正在调用一个可空的变量或者表达式时, 请确保您自己处理了空值。例如:您可以使用 if 条件句、?? 操作符 或是 ?. 操作符来处理可能为空的值。

    // 使用 ?? 操作符来避免将非空变量赋予空值
    int value = aNullableInt ?? 0; // 0 if it's null; otherwise, the integer
    
  • 如果您能确定一条可空的表达式不为空, 您可以在其后添加 ! 让 Dart 处理为非空。

    int? aNullableInt = 2;
    int value = aNullableInt!;
    
  • 如果您想改变一个可空变量的类型,您可以使用 类型转换操作符 (as), 这是 ! 操作符做不到的。

    // 使用了 as 将 num? 转换为 int
    return maybeNum() as int;
    
  • 一旦您开始使用空安全,当操作对象可能为空时, 您将不再能使用 成员访问符 (.)。取而代之的是可空版本的 ?.

    double? d;  print(d?.floor()); // Uses `?.` instead of `.` to invoke `floor()`.
    

四、异步编程

Dart异步原理
Dart 是一门单线程编程语言。
异步 IO + 事件循环

在这里插入图片描述
异步操作

1. Future

Future 对象封装了Dart 的异步操作,它有未完成(uncompleted)和已完成(completed)两种状态。
completed 状态也有两种:一种是代表操作成功,返回结果;另一种代表操作失败,返回错误。

Future<String> fetchUserOrder() {
  //想象这是个耗时的数据库操作
  return Future(() => 'Large Latte');
}

void main() {
  fetchUserOrder().then((result){print(result)})
  print('Fetching user order...');
}

通过.then来回调成功结果,main会先于Future里面的操作,输出结果:

Fetching user order...
Large Latte

Future 同名构造器是 factory Future(FutureOr<T> computation()),它的函数参数返回值为 FutureOr<T> 类型,我们发现还有很多 Future 中的方法比如Future.thenFuture.microtask 的参数类型也是 FutureOr<T>,看来有必要了解一下这个对象。
FutureOr<T> 是个特殊的类型,它没有类成员,不能实例化,也不可以继承,看来它很可能只是一个语法糖。

abstract class FutureOr<T> {
  // Private generative constructor, so that it is not subclassable, mixable, or
  // instantiable.
  FutureOr._() {
    throw new UnsupportedError("FutureOr can't be instantiated");
  }
}

2. async 和 await

想象一个这样的场景:

  1. 先调用登录接口;
  2. 根据登录接口返回的token获取用户信息;
  3. 最后把用户信息缓存到本机。
Future<String> login(String name,String password){
  //登录
}
Future<User> fetchUserInfo(String token){
  //获取用户信息
}
Future saveUserInfo(User user){
  // 缓存用户信息
}

Future 大概可以这样写:

login('name','password')
  .then((token) => fetchUserInfo(token))
  .then((user) => saveUserInfo(user));

换成 asyncawait 则可以这样:

void doLogin() async {
  String token = await login('name','password'); //await 必须在 async 函数体内
  User user = await fetchUserInfo(token);
  await saveUserInfo(user);
}

声明了 async 的函数,返回值是必须是 Future 对象。即便你在 async 函数里面直接返回 T 类型数据,编译器会自动帮你包装成 Future<T> 类型的对象,如果是 void 函数,则返回 Future<void> 对象。在遇到 await 的时候,又会把 Futrue 类型拆包,又会原来的数据类型暴露出来,请注意,await 所在的函数必须添加 async 关键词

await 的代码发生异常,捕获方式跟同步调用函数一样:

void doLogin() async {
  try {
    var token = await login('name','password');
    var user = await fetchUserInfo(token);
    await saveUserInfo(user);
  } catch (err) {
    print('Caught error: $err');
  }
}

语法糖:

Future<String> getUserInfo() async {
  return 'aaa';
}
//等价于:
Future<String> getUserInfo() async {
  return Future.value('aaa');
}

总结

以上内容基本属于 Dart语言的基础部分,我们在学习 Flutter 之前先对Dart有一个简单的了解,那么对于后面的学习会更加顺利。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter 是一种跨平台的移动应用开发框架,能够快速构建高效、美观的应用程序。下面我将介绍从入门到进阶的学习路径,并给出实战携程网应用程序的资料。 1. 入门阶段: - 学习Dart语言基础DartFlutter 的编程语言,掌握其基本语法和特性非常重要。 - 安装Flutter SDK:根据官方指南下载并配置好Flutter开发环境。 - 理解Flutter基础概念:学习Flutter的基本概念,如Widget、State、BuildContext等。 - 创建第一个Flutter应用:通过编写一个简单的计数器应用程序加深对Flutter开发流程的理解。 2. 进阶阶段: - 深入学习Widget:掌握Flutter中的各种Widget,了解它们的层次结构以及常用属性和方法。 - 路由和导航组件:学习如何实现应用程序之间的页面跳转和导航功能。 - 网络请求与数据处理:学习如何使用Flutter的网络请求库,并结合携程网的API接口获取数据。 - 状态管理:掌握不同的状态管理方案,例如Provider、GetX等,以便更好地管理应用程序的复杂状态。 - 自定义控件和动画:学习如何自定义Flutter控件,以及如何使用动画使应用程序更加生动和流畅。 实战携程网app资料: - Flutter官方文档:提供了全面的Flutter开发指南和示例代码,可在Flutter官方网站找到。 - Github上的开源项目:可以在Github上搜索到一些开源的Flutter项目,其中可能包含实现携程网app功能的示例代码。 - 携程网提供的开放API:携程网提供了一些开放接口供开发者使用,可通过API文档了解接口的使用方法,然后在Flutter中进行集成。 通过系统学习和实践,从入门到进阶,您将能够掌握Flutter开发技术,并有能力构建出类似携程网的应用程序。加油!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值