Dart(一)--初入Dart 环境配置&变量&内置类型

作为Flutter开发使用的语言,Dart的学习是必不可少的,它是一门专门为跨平台设计的语言,如果你有kotlin的知识,那么你的学习成本不高,在一定程度上他们很相像

一、Dart环境

1.插件安装

**Android Studio**于2020.3(Arctic Fox) 版本后,都支持Flutter开发,只需要在插件中进行下载安装

先下载安装Dart:

顺便把Flutter也下载安装了:

插件下载

2.Flutter SDK下载与环境变量配置

Flutter开发需要对应的SDK,其中包含了Dart的SDK,下载地址:https://flutter.cn/docs/development/tools/sdk/releases

下载后解压到自己喜欢的目录,我这边是:C:\Program Files\FlutterSDK\flutter,配置环境变量(非必要):

3.创建Flutter项目

选择Flutter SDK的目录:

按照描述填写工程信息并创建:

二、第一个Dart程序

目前我们在**Android Studio**中搭建了Flutter环境,由于Flutter包含了Dart,所以Dart可以直接运行,创建工程后会自动帮我们构建项目目录,我们来到lib目录下进行Dart的学习

1.main函数

main函数是Dart程序的入口,创建一个Dart文件,并编写代码:

main() {
  // 定义一个数字变量
  var number = 42;
  print(number);
}

运行结果:

三、变量

Dart是一个强类型语言,所以我们可以通过指定变量类型的方式去定义变量,如:int i = 42,但Dart不推荐该方式,和Kotlin一样,Dart支持类型推断,我们只需要使用var,后续Dart会自动识别该变量类型

1.类型推断
main() {
  // 指定变量类型
  int i = 42;
  // 使用类型推断
  var a = '1a';

  print(i.runtimeType);
  print(a.runtimeType);
}

运行结果:

2.空安全
2.1 ?可空

如果一个变量可以为空,那么定义该变量时,不初始化或使用强类型+?的组合方式:

main() {
  // 空安全
  int? i = null;
  print(i == null);
  i = 10;
  print(i == null);

  var i2;
  print(i2 == null);
}

运行结果:

Dart编译器在变量为空时会提示你,你可以使用变量?进行后续操作,如果变量为null返回null,否则返回后续操作,非空时则不需要做特别处理:

main() {
  // 空安全
  int? i = null;
  if (i != null) print(i + 2);

  // ? 如果为null返回null,否则返回后续
  print(i?.toString());

  i = 10;
  print(i + 2);
}

运行结果:

2.2 !非空断言

如果你认为可空变量不为空,可以通过!强制调用,当变量为空时,抛出异常:

main() {
  // 空安全
  int? i = null;
  print(i! + 2);
}

运行结果:

3.延迟初始化
3.1 late

使用late关键字申明变量,程序将在使用该变量时才进行创建

// Tortoise类型变量
late var t = Tortoise();

// 定义一个类
class Tortoise {
  var name = "tortoise";

  // 构造实例方法
  Tortoise() {
    print("constructor init");
  }
}

main() {
  print("start");
  print(t.name);
  print("end");
}

运行结果:

Dart编译器在定义非空变量时未赋值的情况进行提示报错,有时你仅仅想延后给该变量赋值,如在检查顶级变量和实例(引用类型)变量时,使用late修饰的变量,编译器就不会对它进行非空判断

4.不可变与常量
4.1 final 不可变

使用final代替var进行定义变量后,该变量不可重新赋值:

4.2 const 常量

const不能修饰实例类型,使用const代替var进行定义变量后,表示该变量是常量,const变量同时也是final的,通常使用在顶级变量与类静态常量中:

4.2 static 静态成员变量

static修饰的成员变量在同类型实例中有且只存在一份,通常和const一起使用,标识一个类静态常量

class Tag {
  static const tag_1 = 10;
  static const tag_2 = 20;
}

main() {
  print(Tag.tag_1);
  print(Tag.tag_2);
}

四、内置类型

内置类型不是Java中的基本类型,它们都带有丰富的函数

1.Number 类型

Dart内置两种数字类型:intdouble

1.1 int
main(){
  // int类型变量
  var i = 10;
  print(i + 20);
  
  // 格式化字符串转换为int,失败抛出异常
  print(int.parse("20"));
}
1.2 double
main(){
  // double类型变量
  var d = 10.45;
  // 向上取整
  print(d.ceil());

  // 格式化字符串转换为double,失败抛出异常
  print(double.parse("20.23"));
}
2.String 类型
2.1 三种标识String

Dart可以使用'内容'"内容"''' 多行内容 '''三种方式表示一个字符串

main() {
  var s1 = 'hello dart';
  var s2 = "hello dart";
  var s3 = '''
    hello
    dart
  ''';
  
  print(s1);
  print(s2);
  print(s3);
}

运行结果:

2.2 ${} 取值占位

在字符串中可以使用${表达式}将表达式结果代替占位符,表达式是一个标识符,可以省略掉{}

main() {
  var name = 'zhangsan';
  print("$name study dart,${name.toUpperCase()}");
}

运行结果:

2.3 r 禁止转义

在字符串前标识r,那么该字符串内容不会转义

main() {
  print(r"study dart \n very happy");
}

运行结果:

3.Boolean 类型

在Dart中使用bool定义布尔变量,用法就是truefalse,比较简单不多做介绍

4.List 类型
4.1 [] 定义List

List类型称之为列表或数组,定义方式由[]包裹元素,内置增删改一系列函数

main() {
  // []包裹item
  var intArr1 = [1, 2, 3];
  List<int>? intArr2;
  
  // 添加一个list
  intArr1.addAll([4, 6]);
  print(intArr1);
}
4.2 … 扩展操作符

定义List时,可以使用......?(空不添加),在初始化时添加别List

main() {
  var intArr1 = [1, 2, 3];
  List<int>? intArr2;

  var intArr3 = [0, ...intArr1];// ...初始化就添加别的List
  var intArr4 = [0, ...?intArr2];// ...?为空不添加
  print(intArr3);
  print(intArr4);
}

运行结果:

5.Set 类型

集合为无序无重复项的容器

5.1 {} 定义Set

Set中不会存在重复元素:

main() {
  var set1 = {1, 1, 1};
  
  // 只含有一个1
  print(set1);
}

运行结果:

5.2 <类型>{} 空集合

可以在{}前使用<类型>创建一个该类型的空集合

main() {
  var set = <String>{};
  set.add("hi");
  set.addAll({"dart", "flutter"});
  
  print(set);
}
6.Map 类型

Map原理和Set相同,存放键值对,键唯一

6.1 {} 定义Map
main() {
  var map = {0: "hi", 1: "dart"};

  print(map[0]);
  print(map[1]);
}

运行结果:

6.2 Map<键类型,值类型>() 空Map

可以通过Map<键类型,值类型>()创建一个指定key类型value类型的空Map

main(){
  var map = Map<String,String>();
}
6.3 添加元素与取值

Map添加元素直接使用[key]赋值即可;取值使用[key],不存在返回空

main(){
  var map = Map<String,String>();
  // 添加或更新键值对
  map['a'] = 'A';
  map['b'] = 'B';
  
  print(map['a']);
  // 没有对应的键,返回null
  print(map['c']);
}

运行结果:

7. Runes 与 grapheme clusters

Unicode 字符的常见方式是使用 \uXXXX,其中 XXXX 是一个四位数的 16 进制数字。例如心形字符(♥)的 Unicode 为 \u2665。对于不是四位数的 16 进制数字,需要使用大括号将其括起来。例如大笑的 emoji 表情(😆)的 Unicode 为 \u{1f600}

main() {
  var hi = "hi \u{1f600}";
  print(hi);
  // 期望只输出😆
  print(hi.substring(hi.length - 1));
}

运行结果:

7.1 grapheme clusters

上面我们期望只输出😆,但是内置函数并不会把 Unicode 字符当作一个字符,如果你需要读写单个 Unicode 字符,可以使用 characters 包中定义的 characters API,需要导入'package:characters/characters.dart'

import 'package:characters/characters.dart';

main() {
  var hi = "hi \u{1f600}";
  print(hi);
  // 期望只输出😆
  print(hi.substring(hi.length - 1));
  print(hi.characters.last);
}

运行结果: