Dart3特性分享

前言:

(dart的发展史,以及flutter的结合dart的关系史)

  1. 2011年10月,谷歌发布了 Dart 编程语言的首个技术预览版。该版本包含了 Dart 语言的基本语法、库以及一个 Dart VM。
  2. 2013年11月,谷歌发布了 Dart 1.0 版本。这个版本是 Dart 的第一个稳定版本,标志着 Dart 正式进入生产环境。
  3. 2015年8月,谷歌发布了 Dart 2.0 版本。这个版本引入了许多重要的语言特性,包括强类型系统、更好的工具链以及更好的性能。
  4. 2018年12月,Flutter 1.0 版本正式发布。Flutter 是一个基于 Dart 的 UI 工具包,用于构建跨平台的移动应用程序。
  5. 2019年:Dart 2.1、2.2 和 2.3 发布。
  6. 2020年:Dart 2.8 和 2.9 发布
  7. 2021年5月,Dart 2.12 版本发布,引入了空安全特性,使得 Dart 更加安全、可靠。引领flutter2.0的变迁。
  8. 2022年5月12日,Dart 3 发布[2023年5月11日Flutter3.10.0发布,开始接入Dart3.0.0]。将只支持健全的 Null 安全,主要语言特性 —— 记录、模式和类修饰符。
  9. Dart最新(V3.4.0):2024年5月14日,Flutter最新版本(V3.22.0):2024年5月14日

Dart和Flutter的关系

Flutter 是一个由谷歌开发的开源用户界面(UI)工具包,用于在移动、Web 和桌面平台上构建高质量的原生用户界面。Flutter 使用 Dart 语言编写,并提供了丰富的 UI 组件、工具和库,使开发者能够快速构建美观、流畅的跨平台应用程序。

Dart 是一种由谷歌开发的现代化、多范式的编程语言,旨在提供更好的性能、更高的生产力和更好的可维护性。它具有类似于 Java 和 JavaScript 的语法,并提供了类似于 Java 的面向对象编程和类似于 JavaScript 的函数式编程特性。Dart 是 Flutter 的核心编程语言,开发者使用 Dart 编写 Flutter 应用程序。

Flutter 和 Dart 之间有密切的关联,它们共同构成了构建跨平台应用程序的技术栈。Flutter 提供了丰富的 UI 组件和开发工具,而 Dart 提供了强大的语言特性和工具链,使开发者能够高效地构建、测试和部署应用程序。Flutter 的框架和工具都是使用 Dart 编写的,因此开发者可以充分利用 Dart 的功能来构建复杂的用户界面和逻辑。

flutter版本对应依赖dart版本关联表: https://docs.flutter.dev/release/archive?tab=macos#macos

Dart是什么

Dart 是一个易用、可移植且高效的语言,适用于在全平台开发高质量的应用程序。

1. 高易用性

使用统一、简洁、强类型的编程语言进行开发,并提供空安全和模式匹配等现代特性。

2. 研发能力提高

反复地修改: 在正在运行的应用中使用热重载立刻看到你的修改。

3. 全平台极速运行

可编译为移动端、桌面端及后端的 ARM、x64、RISC-V 的二进制文件,或是为 Web 平台编译 Javascript & WebAssembly。

Dart的一些用法

try-dart:https://dart.cn/#try-dart https://dartpad.cn/?id=bc63d212c3252e44058ff76f34ef5730

1. 类型校验( check type)

as : Typecast 
is : instanceof 
is! : !instanceof

2. 参数里面的.和…和…

一个点表示对象的某个属性。

两个点(级联操作符)表示给一个对象的某个属性赋值,然后再返回赋值之后的对象实体。

三个点(可变参数):在可容纳元素数组中可以将一个集合展开为另一个集合接入。(简单的条件判断可以,复杂的逻辑抽象到控制器里面处理,UI层不要和逻辑糅合)

column (children:[
    //title1
    //title2,
    if (条件) ...[
       // content1
       // content2    
    ]
]])

//扩展操作
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
//感知空扩展操作(包含if!= null判断)
var list2 = [0, ...?list];
assert(list2.length == 1);

//...是浅拷贝

3. ++i:前置递增操作符

int i = 5;
int result = ++i; // 先递增 i,再将递增后的值赋给 result
print(i); // 输出 6
print(result); // 输出 6

i++:后置递增操作符

int i = 5;
int result = i++; // 先将 i 的值赋给 result,然后再递增 i
print(i); // 输出 6
print(result); // 输出 5

4. ??= 赋值操作符

  • “??=” 是一个赋值操作符,用于给变量赋值,但只有当变量的当前值为 null 时才进行赋值。
  • 如果变量的当前值不为 null,则不进行赋值操作。
int? a = null;
int? b = 5;

a ??= 10; // 当 a 为 null 时,将其赋值为 10
b ??= 10; // 当 b 不为 null 时,不进行赋值操作

print(a); // 输出 10
print(b); // 输出 5

?? 空值合并操作符

  • “??”" 是一个用于判断 null 值并提供默认值的操作符。如果左侧表达式的值为 null,则返回右侧的值作为默认值,否则返回左侧表达式的值。
  • “??”" 不执行赋值操作,只返回一个值。
int? a = null;
int b = 5;

int c = a ?? 10; // 如果 a 为 null,则 c 的值为 10,否则 c 的值为 a 的值
int d = b ?? 10; // 如果 b 不为 null,则 d 的值为 5,否则 d 的值为 10

print(c); // 输出 10
print(d); // 输出 5

5. try {…} on MyException {…} catch (e) {…} finally {…},

可以on 许多不同的异常状况,非业务逻辑的异常可以统一定义,统一捕获处理。

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
  
  rethrow; // Allow callers to see the exception.
}

6. >>>无符号右移(dart2.14之后才支持), >>有符号右移

// >>  高位补符号位(正数0,负数1)
void main() {
  int x = 8; // 二进制表示为 0000 1000
  int y = x >> 2; // 将 x 右移两位,结果为 0000 0010,即 2
  print(y); // 输出 2
}
int number = -1;
int result = number >> 1;
print(result); // 输出: 4294967295

// >>>   高位补0
int number = -1; // 二进制表示为 1111 1111 1111 1111 1111 1111 1111 1111
int result = number >>> 1; // 无符号右移1位,二进制表示为 0111 1111 1111 1111 1111 1111 1111 1111
print(result); // 输出 2147483647

7. 注释写法

//第一种
void main() {
  // TODO: refactor into an AbstractLlamaGreetingFactory?
  print('Welcome to my Llama farm!');
}

//第二种(多行注释)
void main() {
  /*
   * This is a lot of work. Consider raising chickens.

  Llama larry = Llama();
  larry.feed();
  larry.exercise();
  larry.clean();
   */
}

//第三种(类的解释说明,[]内会被解释器高亮,更易识别)
/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
///
/// Just like any other animal, llamas need to eat,
/// so don't forget to [feed] them some [Food].
class Llama {
  String? name;

  /// Feeds your llama [food].
  ///
  /// The typical llama eats one bale of hay per week.
  void feed(Food food) {
    // ...
  }

  /// Exercises your llama with an [activity] for
  /// [timeLimit] minutes.
  void exercise(Activity activity, int timeLimit) {
    // ...
  }
}

8. 注解, @deprecated、 @override、@protected 和 @proxy。@override 和 @proxy 示例请参考 Extending a class

class Television {
  /// Use [turnOn] to turn the power on instead.
  ('Use turnOn instead')
  void activate() {
    turnOn();
  }

  /// Turns the TV's power on.
  void turnOn() {...}
  // ···
}

//自定义注解(和模型的区别,注解类必须是一个const修饰的常量类)
class Todo {
  final String who;
  final String what;

  const Todo(this.who, this.what);
}

('Dash', 'Implement this function')
void doSomething() {
  print('Do something');
}

9. list和map的深浅拷贝

//list
list.add()//浅拷贝
list.addAll()//浅拷贝
list.from()//深拷贝(只针对基础类型int,string。。。,如果有模型,还需要模型的fromjson和tojson来构建)

//map
map.addAll()//浅拷贝
Map<String, dynamic> obj = JSON.jsonDecode(JSON.jsonEncode(goAlarmData)); //深拷贝

10. Records记录(dart3.0以及以后)

可以优雅的适用于多参数返回(不用特意创建一个类,或者避免使用其他集合类型(如List或Map)会失去类型安全性问题)

Records是一种匿名的、不可变的聚合类型。与其他集合类型一样,它们允许您将多个对象捆绑到单个对象中。与其他集合类型不同,Records是固定大小的、异构的和类型化的。

Records字段可以通过内置getter访问。Records是不可变的,所以字段没有setter。

命名字段公开相同名称的getter。位置字段暴露了名称$的getter,跳过了命名字段:

var record = ('first', a: 2, b: true, 'last');

print(record.$1); // Prints 'first'
print(record.a); // Prints 2
print(record.b); // Prints true
print(record.$2); // Prints 'last'

//Records中的每个字段都有自己的类型。同一Records中的字段类型可以不同。无论从Records中访问哪个字段,类型系统都知道每个字段的类型: 
(num, Object) pair = (42, 'a');
 
var first = pair.$1; // Static type `num`, runtime type `int`.
var second = pair.$2; // Static type `Object`, runtime type `String`.

//如果两条Records具有相同的形状(字段集),并且它们对应的字段具有相同的值,则它们是相等的。由于命名字段的顺序不是Records形状的一部分,因此命名字段的顺序不会影响相等性
// 例如:
(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);
print(point == color); // Prints 'true'

({int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({int r, int g, int b}) color = (r: 1, g: 2, b: 3);
print(point == color); // Prints 'false'. Lint: Equals on unrelated types.

11. 控制流操作(Control-flow operators)

var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];

//if-case是一个匹配关系
var nav = ['Home', 'Furniture', 'Plants', if (login case 'Manager') 'Inventory'];

var listOfInts = [1, 2, 3];
var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
assert(listOfStrings[1] == '#1');

12. 匹配Patter

var first = 2var last = 10;
const a = 'a';
const b = 'b';

switch (obj) {
// Matches if 1 == obj.
  case 1:
    print('one');

  // List pattern [a, b] matches obj first if obj is a list with two fields,
  // then if its fields match the constant subpatterns 'a' and 'b'.
  case [a, b]:
    print('$a, $b');

  // Matches if the value of obj is between the
  // constant values of 'first' and 'last'.
  case >= first && <= last:
    print('in range');
    
//匹配到一个Records,只有两个元素,使用的时候a取值第一个元素,b取值最后一个元素
  // Matches if obj is a record with two fields,
  // then assigns the fields to 'a' and 'b'.
  case (var a1, var b1):
    print('a1 = $a1, b1 = $b1');
    //Records只有两个int类型的元素,且第一个大于第二个
  case (int a2, int b2) when a2 > b2:
    // If false, prints nothing but proceeds to next case.
    print('First element greater');
}

//逻辑或 对于在switch表达式或语句中匹配共享多个用例体非常有用:
var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
};

//数组赋对象
var numList = [1, 2, 3];
// List pattern [a, b, c] destructures the three elements from numList...
var [a, b, c] = numList;
// ...and assigns them to new variables.
print(a + b + c);


//map
Map<String, int> hist = {
  'a': 23,
  'b': 100,
};
for (var MapEntry(key: key, value: count) in hist.entries) {
  print('$key occurred $count times');
}

var json = {
  'user': ['Lily', 13]
};
var {'user': [name, age]} = json;

if (json case {'user': [String name, int age]}) {
  print('User $name is $age years old.');
}

13. 模式匹配类型(dart3.0)

//or
var isPrimary = switch (color) {
  Color.red || Color.yellow || Color.blue => true,
  _ => false
};

//and
switch ((1, 2)) {
  // Error, both subpatterns attempt to bind 'b'.
  case (var a, var b) && (var b, var c): // ...
}

//其他逻辑符
String asciiCharType(int char) {
  const space = 32;
  const zero = 48;
  const nine = 57;
  return switch (char) {
    < space => 'control',
    == space => 'space',
    > space && < zero => 'punctuation',
    >= zero && <= nine => 'digit',
    _ => ''
  };
}

//cast (如果不符合会抛异常)
(num, Object) record = (1, 's');
var (i as int, s as String) = record;

//Null-assert
List<String?> row = ['user', null];
switch (row) {
  case ['user', var name!]: // ...
  // 'name' is a non-nullable string here.
}

//Object匹配并取值
switch (shape) {
  // Matches if shape is of type Rect, and then against the properties of Rect.
  case Rect(width: var w, height: var h): // ...
}

//通配符_
var list = [1, 2, 3];
var [_, two, _] = list;

switch (record) {
  case (int _, String _):
    print('First field is int and second is String.');
}

14. 注意||&&混用(右向左)

x = true;
y = true;
z = false;
// ...
x || y && z => 'matches true',
(x || y) && z => 'matches false',
// ...

15. 其他元素匹配

var [a, b, ..., c, d] = [1, 2, 3, 4, 5, 6, 7];
// Prints "1 2 6 7".
print('$a $b $c $d');

var [a, b, ...rest, c, d] = [1, 2, 3, 4, 5, 6, 7];
// Prints "1 2 [3, 4, 5] 6 7".
print('$a $b $rest $c $d');

16. 枚举

//交通工具
enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });
  //轮子数量
  final int tires;
  //乘客数量
  final int passengers;
  //每公里碳排放
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round();

  bool get isTwoWheeled => this == Vehicle.bicycle;

  
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}

17. 类型修饰符(dart3.0)

abstract class Vehicle {
  void moveForward(int meters);
}

//abstract抽象类,只定义不实现(不能实例化,可被继承,可被接口实现implements)
import 'a.dart';
// Error: Can't be constructed.
Vehicle myVehicle = Vehicle();
// Can be extended.
class Car extends Vehicle {
  int passengers = 4;
  // ···
}
// Can be implemented.
class MockVehicle implements Vehicle {
  
  void moveForward(int meters) {
    // ...
  }
}

//base 基类,(可以实例化,可继承,不能被接口实现)
import 'a.dart';
// Can be constructed.
Vehicle myVehicle = Vehicle();
// Can be extended.
base class Car extends Vehicle {
  int passengers = 4;
  // ...
}
// ERROR: Can't be implemented.
base class MockVehicle implements Vehicle {
  
  void moveForward() {
    // ...
  }
}

//final 修饰防止类型之外的实例化,不可继承不可接口实现
import 'a.dart';
// Can be constructed.
Vehicle myVehicle = Vehicle();
// ERROR: Can't be inherited.
class Car extends Vehicle {
  int passengers = 4;
  // ...
}
class MockVehicle implements Vehicle {
  // ERROR: Can't be implemented.
  
  void moveForward(int meters) {
    // ...
  }
}

//interface 定义接口实现, 不可继承,可实例化,可接口实现
import 'a.dart';
// Can be constructed.
Vehicle myVehicle = Vehicle();
// ERROR: Can't be inherited.
class Car extends Vehicle {
  int passengers = 4;
  // ...
}
// Can be implemented.
class MockVehicle implements Vehicle {
  
  void moveForward(int meters) {
    // ...
  }
}

//sealed 密封。要创建已知的,可枚举的字类型集。不能直接实例化,可继承,可接口实现
sealed class Vehicle {}
class Car extends Vehicle {}
class Truck implements Vehicle {}
class Bicycle extends Vehicle {}

// ERROR: Can't be instantiated.
Vehicle myVehicle = Vehicle();
// Subclasses can be instantiated.
Vehicle myCar = Car();

String getVehicleSound(Vehicle vehicle) {
  // ERROR: The switch is missing the Bicycle subtype or a default case.
  return switch (vehicle) {
    Car() => 'vroom',
    Truck() => 'VROOOOMM',
  };
}

//mixin 混入,在现有类的基础上,引入一些新的变量。
https://blog.csdn.net/BUG_delete/article/details/135551746

类型修饰符和功能速查表: https://dart.cn/language/modifier-reference

18. stream流

//单订阅流(这种 Stream 只能设置一次监听。重复设置则会丢失原来的事件,而导致你所监听到的剩余其它事件毫无意义),多订阅流,单订阅转多订阅
//处理 Stream 的方法
Future<T> get first;
Future<bool> get isEmpty;
Future<T> get last;
Future<int> get length;
Future<T> get single;
Future<bool> any(bool Function(T element) test);
Future<bool> contains(Object? needle);
Future<E> drain<E>([E? futureValue]);
Future<T> elementAt(int index);
Future<bool> every(bool Function(T element) test);
Future<T> firstWhere(bool Function(T element) test, {T Function()? orElse});
Future<S> fold<S>(S initialValue, S Function(S previous, T element) combine);
Future forEach(void Function(T element) action);
Future<String> join([String separator = '']);
Future<T> lastWhere(bool Function(T element) test, {T Function()? orElse});
Future pipe(StreamConsumer<T> streamConsumer);
Future<T> reduce(T Function(T previous, T element) combine);
Future<T> singleWhere(bool Function(T element) test, {T Function()? orElse});
Future<List<T>> toList();
Future<Set<T>> toSet();

//修改 Stream 的方法
Stream<R> cast<R>();
Stream<S> expand<S>(Iterable<S> Function(T element) convert);
Stream<S> map<S>(S Function(T event) convert);
Stream<T> skip(int count);
Stream<T> skipWhile(bool Function(T element) test);
Stream<T> take(int count);
Stream<T> takeWhile(bool Function(T element) test);
Stream<T> where(bool Function(T event) test);
Stream<E> asyncExpand<E>(Stream<E>? Function(T event) convert);
Stream<E> asyncMap<E>(FutureOr<E> Function(T event) convert);
Stream<T> distinct([bool Function(T previous, T next)? equals]);
Stream<T> handleError(Function onError, {bool Function(dynamic error)? test});
Stream<T> timeout(Duration timeLimit,
    {void Function(EventSink<T> sink)? onTimeout});
Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer);

//流合并RxDart

善于使用类自有的操作符

1. offset

var rect = Offset(0, 0) & Size(100, 100);
// == Rect.fromLTWH(dx, dy, other.width, other.height)

double get distance => math.sqrt(dx * dx + dy * dy);

double get direction => math.atan2(dy, dx);
//四则运算+-*/
Offset operator -(Offset other) => Offset(dx - other.dx, dy - other.dy);

最后

分享一个低代码平台开发flutter app的工具blup https://www.blup.in/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值