# 「Flutter」成长笔记 - Dart 基础入门

# 1 / 编写一个 Hello World 并运行

Dart通过 main() 方法作为程序入口

void main(){
    print('Hello world')  // 控制台打印
};
1
2
3

# 2 / 变量与常量

# 1 - 变量

通过 var 声明一个变量(这一点与Javascript很像),然后可以给变量赋值不同的值

若声明后未初始化,默认为null

❗ 注意: Dart是一门强类型语言(与Javascript不同),在第一次赋值时,如果已经确定是字符串类型,则不能更改为别的类型。 如果真的想改变Dart中的字符串类型,可以使用dynamic关键字

# 2 - 常量

如果想设置一个常量,即让一个变量不可变,那么可以使用final或者const进行修饰,例如

var number;
number = 15;
print('A的年龄是 $number 岁');

number = '20';  // 注意,变量类型是可以变的
print(number);

final c = 30;  // final 修饰的变量只能被声明一次
print(c);

const d = 50;
print(d);
1
2
3
4
5
6
7
8
9
10
11
12

🔺 那么constfinal的区别是什么?

const 变量是一个编译时常量,而 final 变量在第一次使用时被初始化(const变量是隐式的final)。实例变量可以是 final,但不能是 const。如果常量是类别级的,可以使用 static const,例如 static const PI = 3.1415

# 3 - 内置类型

Dart内置了一下类型:

  • Number(数值型)
  • String(字符型)
  • Boolean(布尔型)
  • List(列表)
  • Map(键值对)
  • Runes(符号字符)
  • Symbols(标识符)

# 3.1 - 数值型

数值型分整型(int)和浮点型(double),可以用 numintdouble进行声明

❗ 注意: num声明的变量加入的是int型,还可以被改成double型,但是,反过来int声明的变量不能再赋值为double

// Right
num a = 10;
a = 10.1;

// Wrong
int b = 20;
b = 20.1;
1
2
3
4
5
6
7

我们看一下源码,就可以理解了

abstract class int extends num
abstract class double extends num
1
2

# 3.2 - 数值型操作

  • 运算符: + 、- 、* 、/、~/ 、%
  • 常用属性: isNaN 、isEven 、isOdd 等
  • 常用方法:round() 、floor() 、ceil() 、toInt() 、toDouble() 、abs()

在 Dart 2.0里,如果我们声明的是 double 型,且值为int型时,int型会自动转换成double型,例如

double a = 10;  // 打印出来为 10.0
1

也可以通过API来手动转换

print(a.toDouble());
1

# 3.3 - 字符串

在 Dart 中字符串有以下几种创建方式:

  • 使用单引号,双引号创建字符串
  • 使用三个引号或双引号创建多行字符串
  • 使用 r 创建原始 raw 字符串

# 3.4 - 字符串操作

  • 运算符:+ 、* 、== 、[]
  • 插值运算符:${expression}
  • 常用属性:length 、isEmpty 、isNotEmpty
  • 常用方法:contains() 、subString() 、startsWith() 、endsWith() 、indexOf() 、lastIndexOf() 、toLowerCase() 、toUpperCase() 、trim() 、trimLeft() 、trimRight() 、split() 、replaceAll()

关于字符串的一些Api和属性,可以浏览 https://www.jianshu.com/p/3aa5bada902d

❗ 注意: 字符串中单引号里面嵌套单引号,或者双引号里面嵌套双引号,必须在前面加反斜杠进行转意,这个与Javascript里字符串很像。(建议双引号里面嵌套单引号混合使用)

另外,在 Dart 里,可以进行单行拼接,也可以多行拼接,例如:

String str1 = 'ha' 'ha';    // 单引号空格拼接
String str2 = "ha" "ha";    // 双引号空格拼接
String str3 = 'ha' + 'ha';    // 单引号加号拼接
String str4 = "ha" + "ha";    // 双引号加号拼接

// 使用三引号拼接多行字符串
String str5 = '''
    Dart 入门
    Dart 进阶
''';

String str6 = """Dart 入门
    Dart 进阶""";
1
2
3
4
5
6
7
8
9
10
11
12
13

最后,介绍一下插值表达式,即 ${expression}

double iphone = 11000.0;
print('最新Iphone价格为 $iphone');
1
2

# 3.5 - 布尔型

布尔型通常用在if条件判断中

  • 使用 bool 表示布尔型
  • 布尔值只有 true 和 false
  • 布尔值式编译时常量
  • 可以在 debug 模式下通过 assert 断言函数判断布尔值。如果不为真,会引发异常并终止程序往下运行,这在开发时非常有用
var a = '';
assert(a.isEmpty);

var nullValue;
assert(nullValue == null);
1
2
3
4
5

# 3.6 - List / 数组

在Dart中,List表示集合,这其实和数组是同一个概念。创建方法如下:

// 创建 List
var list1 = [1,2,3];

// 通过构造函数创建 List
var list2 = new List();

// 创建一个不可变的 List
var list3 = const[1,2,3];
1
2
3
4
5
6
7
8

在实际开发中,我们经常需要访问List里面的内容,可以通过 list[] 方式来访问,比如 list[1]

有的时候也需要改变 List 里面的内容,可以这样写:list[0] = 0,但是如果试图改变一个不可变的 List,就会报错

List 中的常有方法有:

  • length() - 获取集合长度
  • add() - 增加一个元素
  • insert() - 在指定位置插入元素
  • remove()
  • clear()
  • indexOf() - 获取指定元素位置
  • lastIndexOf() - 获取最后一个指定元素位置
  • sort() - 排序
  • asMap()
  • forEach() - 传入一个方法,遍历执行
  • shuffle() - 随机打乱 List 元素顺序

# 3.7 - Map

在 Dart 中,Map 以 key-value(键值对)形式存储,键和值都可以是任何类型的对象,每个键只出现一次

  • 通过直接声明的方式创建一个Map,里面写keyvalue,并且用逗号隔开,例如:
Map game = {
    'name': 'Switch',
    'company': '任天堂'
};
1
2
3
4
  • 创建一个不可变的Map,只需在Map前面加入const,例如
Map game = const{
    'name': 'Switch',
    'company': '任天堂'
};
1
2
3
4
  • 通过构造函数先声明,再赋值,例如
Map game= new Map();
game['name'] = 'Switch';
game['company'] = '任天堂';
1
2
3

· 以上的代码可以通过 变量名[Key] = value 的形式修改 Map 中的元素(键值)
· 我们也可以通过调用 removeclear 方法来移除元素

game.remove('name');    // 把key为 'name' 的元素移除
game.clear();   // 清空整个 Map 集合
1
2

# 3.8 - dynamic / Object

在 Dart 里,一切皆对象,而且这些对象的父类都是Object 当没有明确类型时,编译的时候会根据值来明确类型,例如

var name1 = 'abc';
Object name2 = 'def'
dynamic name3 = 'hij'
1
2
3

以上写法都没有问题,但是 Dart 不建议我们这样做,在实际开发中,我们应尽量为变量确定一个类型,这样做可以提高安全性,加快运行速度

如果不指定类型,则在debug模式下类型会时动态的,所以还是建议以下写法

String a = 'abc';
1
  • dynamic 使用 dynamic 时则是告诉编译器,我们不用做类型检测,并且知道自己在做什么。如果我们调用一个不存在的方法时,会执行noSuchMethod()方法。 默认情况下(在 Oject 里实现)它会抛出NoSuchMethodError。举个例子:
dynamic obj = '小明';
obj['age'] = 18;
1
2

这段代码编译时可以通过,但实际运行中会抛出NoSuchMethodError异常

为了在运行时可以对类型进行检测,我们可以使用asis关键字,例如

dynamic obj = <String, int>();
if(obj is Map<String, int>){
    obj['age'] = 20
};
var map = obj as Map<String, int>;
1
2
3
4
5

# 4 - 运算符

计算机语言常用的几个运算符就不多说了,我们看一下 Dart 常用和特有的几个运算符

  • 三目运算符

三目运算符在别的计算机语言中也右,在 Flutter 中用得较多,通常与 state 状态管理结合,用来判断组件得状态,其基本用法如下

expression1 ?? expression2  // 如果expression1非空,则返回其值,否则返回expression2的值


// 具体 Demo
int a = 20;
var value = a > 10 ? a : 0;
1
2
3
4
5
6
  • ~/ 除法,返回一个整数结果(取商)
var value = 12~/7;
print(value);   // 1
1
2
  • 级联操作符

级联可以对同一个对象执行一系列的操作。除了函数调用,你也可以存取统一对象上的字段。这可以减少创建临时变量的步骤,写出更优美的代码

querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

// 等价于
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
1
2
3
4
5
6
7
8
9
10
  • as / is / is!
    • as:判断属于某种属性
    • is:如果对象具有指定的类型,则为 true
    • is!:如果对象具有指定的类型,则为 false

# 5 - 异常捕获

Dart可以抛出任意类型的对象。方式如下

throw Exception('I am Error')
1

有的时候,我们需要捕获异常,确保程序的健壮性,例如

try{
    // 捕获特定类型的异常
}on AuthorizationException catch(e){
    // 捕获特定类型的异常,但不需要这个对象
}on Exception{
    // 捕获所有异常
}catch(e){
    // ...
}finally{
    // ...
}
1
2
3
4
5
6
7
8
9
10
11