本篇可随意转载!Update 2022.05.24

前言

Dart是Google设计用来统一前端开发的编程语言,是Flutter框架的默认编程语言。

代码在线调试:地址

本文要求读者有Java语言背景,因为本文只介绍了Dart跟Java不一样的特性,信息量非常大。

1. Dart语言特性

1.1 字面变量:

// 可用单/双引号,可用模板字符串:$xx打印变量
num aNumber = 1;
print('this is a $aNumber');

1.2 不固定类型变量:

var aNumber = 123;
dynamic b = '123';

未赋值变量默认是null。

1.3 常量:

const age = 18;
// 可以将运行时的值赋值给final变量
final age2 = DateTime.now();

1.4 数值类型:num int double

// 结果是3
print(3.8.toInt());
// 四舍五入
print(3.8.round());
// 保留4位小数
print(3.1415926.toStringAsFixed(4));
// 取余数=1
print(10.remainder(3));
// 数值比较,相同:0;大于:1;小于:-1
print(10.compareTo(12));
// 科学计数法: 1.00e+3
print(1000.toStringAsExponential(2));
// 非数字类型: NAN 如下:
var n = 0/0;
print(n.isNaN);

1.5 布尔类型

// 布尔值
bool a = true;
var flag;
// 下面报错,flag不包含null类型
if( flag ){
    print('true');
}else{
    print('false');
}

1.6 List类型

List alist = [];
// 限制List中的变量类型
List aIntList = <int>[];
List b = new List.empty(growable:true);

// 填充3个0
List c = new List.filled(3, 0);

// 扩展操作符
List d = [1, 2, 3];
List e = ['a', ...d];

// List长度,不用小括号
print(e.length);
// List判空,不用小括号
print(e.isEmpty);

// 删除指定下标元素
e.removeAt(1);
// 连接列表元素
List f = ['fuck', 'you'];
print(f.join('-'));

// 遍历列表操作 forEach() map() where() any() every() expand()
var numbers = [1, 2, 3];
List list = ['a', 'b', 'c'];
numbers.forEach((element){
    print(element);
}); 

var newNumbers = numbers.map((e){
    return e*e;
});
print(newNumbers);
bool isOdd(n) => n%2==1;
var oddNumbers = numbers.where((element) => isOdd(element));
print(oddNumbers);

print(numbers.any(isOdd));
print(numbers.every(isOdd));

var twoDim = [[1, 2], [3, 4]];
var flattened = twoDim.expand((element) => element).toList();
print(flattened);

1.7 Set类型

var set1 = {'a', 'b', 'c'};
var set2 = new Set();
set2.addAll(['c', 'd', 'e']);
// 求两个Set的交集
print(set1.intersection(set2));
// Set无法用下标访问元素
print(set1.first);
print(set1[1]);
// 求并集要求两个集合类型相同
print( set1.union(set2) );

1.8 Map类型

// 使用var, dynamic, Map声明类型都行
Map person = {
    "name": "Alex",
    "age": 20
};
// 增加元素
person.putIfAbsent('gender', ()=>'male');
print(person);
// 条件删除
person.removeWhere((key, value) => key == 'gender');
print(person);

1.9 其他类型

Runes

utf-32,参考网址: https://copychar.cc

Runes input = new Runes('\u{1f680}');
print(new String.fromCharCodes(input));

Symbol类型

var a = #abc;
var b = new Symbol('abc');

1.10 运算符

  var a=21;
  var b=5;
  var c = a % b;
  // 地板除
  var d = a ~/ b;
  print(c);
  print(d);
  print("$a与$b相除等于$d余数是$c");

1.11变量避空

  int a = 6;
  int b;
  a??=10; //a为空则赋值,不为空则不赋值
  b??=10; 
  print("$a---$b");
  int c;
  var d = c ?? 7; //c为空则赋值,不为空则不赋值
  print("d=$d");

1.12 类型转换

  String price = "199.9";
  try{
    double p = double.parse(price); //String类型转换double
    print(p);
  }catch(err){
    print(err);
  }

1.13 条件属性访问

var m;
print(m?.length); //此处返回null而不是抛出异常

1.14 级联访问

Set a = new Set();
a..add('1')..add('2')..remove('1');

2.Dart函数

2.1 函数本身也是对象

  // 函数是对象 -->true
  print( (){} is Object );

2.2匿名函数

  var printNumber = () {
    print("anonymous function, print a number");
  };

2.3箭头函数

 var list = [1, 2, 3];
 list.forEach((element)=>{
    print(element)
});

2.4立即执行函数

(() => print('self running'))();

2.5 闭包

函数里包含局部变量并嵌套子函数,并返回子函数。它可以让变量不占用全局作用域,且全局可访问。

void main() {
  var fn = () {
    int n = 0;
    print("init n=$n");
    return () {
      n++;
      print("return n=$n");
    };
  };
  // n=1
  fn()();
  // n=1
  fn()();

  // runner为函数对象
  var runner = fn();
  // 执行函数对象返回n=1
  runner();
  // 再次执行函数对象返回n=2
  runner();
}

2.6 函数可选参数

// 中括号
void userInfo(String name, [int age = 0 ]){
    print('user name = ${name}, age=${age}');
}

2.7 函数命名参数

// 大括号
void userInfo(String name, {int age = 0}){
    print('user name = ${name}, age=${age}');
}

void main() {
  // 直接用名字+冒号
  userInfo('Alex', age:30);
}

2.8函数作为参数

var func = (value)=>print('this is ${value}');
List list = [1,2,3];
list.forEach(func);

2.9 异步函数 async await

3. 类

实例化类的new关键字可以省略。

3.1 普通构造函数

class Point{
    ...
    // 无body构造函数
    Point(this.x, this.y);
}

3.2 命名构造函数

    Point.anyNamexxx({x:1, y:1}){
      this.x = x;
      this.y = y;
    }
}

3.3常量构造函数 const +构造函数

3.4 工厂构造函数 factory+构造函数

3.5 访问修饰符

dart中没有private,protected,public,默认就是public,私有的变量和方法以_开头:

class A{

   int _aaa = 0;

   void _doxx(){
     print('_aaa');
   }
}

注意: main和class在一个文件的时候,不能保证私有,类需要单独用文件存储。

3.6 get和set关键字

class Sharp{
  num r = 1;
  num get area{
    return r*r;
  }
  set setR(num r){
    this.r = r;
  }
  
}

void main() {
  Sharp sharp = new Sharp();
  print(sharp.area);
  sharp.setR = 10;
  print(sharp.area);
}

3.7 初始化列表

class Rect {
    int x;
    int y;
    Rect(): x = 2, y = 3 {
        print('x=${x}, y=${y}');
    } 

    // 初始化列表的特殊用法- 重定向构造函数
    Rect.origin(int x, int y) : this(x, y);
}


4. 接口和Mixin

4.1 接口

Dart中的接口就是一个abstract class(也可以用普通类),不需要interface关键字做修饰。类通过implements关键字实现接口。

abstract class Processor{
    String cores;
    arch(String name);
}

class Phone implements Processor {
    @Override
    String cores;

    @Override
    arch(String name) {
        print('手机芯片: $name');
    }
}

4.2 Mixin

使用类声明Mixin

class A {
   void printA(){
       print('A');
   }
}

使用类声明的Mixin,不能继承除了Object以外的任何类,也不能有构造函数

使用Mixin关键字

mixin B {
    void printB(){
        print('B');
    }
}

普通类通过with来使用Mixin

class CommonClass with A, B{

}

void main(){

    var c = new CommonClass();
    c.printA();
    c.printB();
}

5. 泛型

泛型分为:泛型类,泛型函数,泛型接口。

5.1泛型函数一般格式

返回类型 函数名<输入类型> (参数类型 参数)
{
    函数体
}

5.2泛型接口

abstract class Cache<T> {
    getByKey(String key);
    void setByKey(String key, T value);
}

class MemoryCache<T> implements Cache<T> {
    @Override
    getByKey(String key){
        return null;
    }

    @Override
    void setByKey(String key, T value){
        print('文件缓存 key=${key}, value=${value}');
    }
}

5.3泛型的上界extends

class Fruit{

}

class Apple extends Fruit{

}

class A<T extends Fruit>{
    String toString() => "Instance of 'Fruit<$T>'";
}

6. 枚举

枚举定义

enum Color{red, green, yellow}

枚举的值

List<Color> colors = Color.values;

枚举的索引值

Color.green.index

7. 库

一般用小写+下划线表示一个库

library my_test_lib

7.1库

  • 自定义库( import ‘库的位置/库名称.dart’ )
  • 系统库(import ‘dart:库名称’)
  • 部分引入(import ‘lib/my_test_lib/myfunctions.dart’ show func1, func2)
  • 排除引入(import ‘lib/my_test_lib/myfunctions.dart’ hide func1, func2)
  • 使用别名解决冲突(import ‘lib/my_test_lib/myfunctions.dart’ as myfunctions)
  • 延迟引入(import ‘lib/my_test_lib/myfunctions.dart’ deferred as myfunctions)

7.2 主子库

lib myfunctions
part of myfunctions;

int add(int x, int y){

}
part of myfunctions;
int concat(String a, String b){
    
}

7.3 自定义库

特定的目录结构,pubspec.yaml

8.Dart内置库-isolate

import 'dart:async';
import 'dart:isolate';

main(List<String> args) {
  start();

  print("start");
}

Isolate isolate;

int i = 1;

void start() async {
  //接收消息的主Isolate的端口
  final receive = ReceivePort();

  isolate = await Isolate.spawn(runTimer, receive.sendPort);

  receive.listen((data) {
    print("Reveive : $data ; i :$i");
  });
}

void runTimer(SendPort port) {
  int counter = 0;
  Timer.periodic(const Duration(seconds: 1), (_) {
    counter++;
    i++;
    final msg = "nitification $counter";
    print("Send :$msg ;i :$i");
    port.send(msg);
  });
}

9.Dart原生流Stream

1对1的流(不能同时监听listen):

void main() {
  StreamController<String> controller = StreamController<String>();

  // controller.stream.listen((item) => print(item));
  controller.sink.add("Item1");
  controller.sink.add("Item2");
  controller.sink.add("Item3");
  controller.stream.listen((item) => print("a " + item));
  controller.close();
}

运行结果:

[Running] dart "/Users/ouyang/app/flutter/isolate_test/stream.dart"
a Item1
a Item2
a Item3

广播流:

void main() {
  StreamController<String> controller = StreamController<String>.broadcast();

  controller.stream.listen((item) => print(item));
  controller.stream.listen((item) => print("a " + item));

  controller.sink.add("Item1");
  controller.sink.add("Item2");
  controller.sink.add("Item3");

  controller.close();
}

运行结果:

Item1
a Item1
Item2
a Item2
Item3
a Item3

10.RxDart

RxDart的开发者阐述他们的设计思想视频(需要翻墙)。里面讲到了如何做类型增强?为何不像其他rx框架封装自己的Observables对象而是选择增强dart原生对象?包括Flutter开发者为什么引入StreamBuilder?它又是如何增强dart原生Stream、StreamController、Subject?

下面表格列出了Observables和Dart的Streams的区别:

既然抛弃了Observables,那么RxDart的作者是如何做到的呢:

  1. Stream Classes 创建具有特定功能的流,例如将多个流合并在一起。
  2. Extension Method  将源流转换为具有不同功能的新流,例如节流或缓冲事件
  3. Subjects 具有额外能力的流控制器

具体细节请看这里

分类: flutter