自上一次使用Flutter和Dart已过去了快3年了。很多基础知识已经忘记了,再加上这3年Dart和Flutter的不断更新迭代,完全跟不上了。先通过这次记笔记的方式来系统的重学一遍Flutter。但在学Flutter之前,先系统的过一遍Dart的语言。毕竟Flutter的是基于Dart去开发,只有对Dart有一定的了解,再学习Flutter的时候,尤其是一些高级用法的的时候才不至于看不懂。
初识Dart
Dart的安装是在安装Flutter的时候跟随在Flutter包内的。因此,不需要单独的去安装Dart。 在Dart语言中,你能发现Java的影子,也能看到Kotlin和JavaScript的影子。为什么这么说?因为Java中,我们可执行代码的后面都需要";"符号,在比如class类的声明方式,构造方法等,当然,也不仅仅就这么一点点,还有很多其他类似的地方,慢慢学,慢慢体会。 如:
bash
print("Hello world!");
JavaScript的影子如:
dart
import 'package:http/http.dart' as http;
var p = 100;
var p = "100";
print("the value of P:$p")
其实对于一个具有开发经验的人来说,尤其是有Java,kotlin或者是JavaScript经验的人来说上手Dart还是非常简单的。
Dart 变量声明
我们学习一门语言的时候,首先要了解的就是这个语言如何声明变量。
- 该语言的基础类型有哪些?
- 如何声明变量?
- 未初始化的变量的默认值是什么?
- 如何声明延迟初始化的参数?
- 如何声明常量?
- 变量的可见性如何控制?
1. 基础类型
其实大多数语言都差不多,基础类型都是:数字,浮点,布尔,字符串。只不过每个语言定义关键字略有小区别,比如大小写,或者有些语言会在数字类型再细分一些数字类型的长短之类的。那么Dart中的基础类型有哪些呢?
ini
int i = 100;
double d = 100.0;
String s = "string";
bool b = true;
整体和其它语言没什么大的区别。唯一需要说明一下的是int类型。它和Java的int类型不一样,Java中针对数字类型的大小有比较明确的区分,如int是32位,long是64位,超出这个范围就会出现溢出。但是Dart中不会,Dart语言中的int是一个通用数字类型,默认位数是和系统保持一致,比如32位系统中默认就是有符号32位,64位系统中默认就是有符号64位。如果操作变量的值比这个64位还要更大,那Dart中也会自动改变为大数变量。所以在Dart中可以大胆的用int去表示任何整数类型的数值,不会存在溢出这个问题。double也是一样的,可以大胆的去声明浮点类型的数值。
2. 变量声明
Dart语言是一个类型安全的语言,也叫强类型语言;但即使这样,Dart中声明变量的时候,依然可以使用隐士声明,因为Dart也具有类型推断的能力。 如:
ini
var n = 100; //这个变量会自动声明称int类型。
var s = "100"; //这个变量会自动声明称字符串类型。
但Dart语言不是弱类型语言,因此和弱类型语言还有一点区别,一旦变量类型确定了,或者说初始化了,那么该变量的类型就确定了,不可更改了。如果你强行给他赋值一个不一样的类型,编译器就会报错了。 如:
perl
var n = 100; //这个变量会自动声明称int类型。
n = "100"; // 因为前面已经赋值了100,所以确定了n为数字类型,如果你再给他赋值一个string类型的值,那就会出现类型转换的错误:
// A value of type 'String' can't be assigned to a variable of type 'int'. (Documentation) Try changing the // type of the variable, or casting the right-hand type to 'int'.
除了前面提到这些通过var声明变量的方式之外,还可以通过显示类型的方式声明变量。这点和Java非常相似。 如:
ini
int number = 100;
String name = "Dart";
bool isDone = true;
3. 默认值
Dart语言有一个空安全的特性,因此在声明一个变量之后,在它被使用之前必须初始化,除非它是一个可以为空的变量。也就是说如果你像前面这样的方式去声明一个变量的话,这个变量必须设置一个默认值,也就是初始化的值。否则你就得把它声明为一个可为空的变量。 如:
ini
int count = 0;
错误用例:
scss
int lineCount; //这样声明则表示count的值不可为空,它不会在没初始化的时候自动设置0这样的默认值。
if (weLikeToCount) {
lineCount = 0;
}
print(lineCount); //这个时候就会报错了,因为wLikeToCount这个值为false的时候,lineCount就不会被赋值了,但是它又是被声明为不可为空的变量,因此这个地方就会编译不通过了。
但间接初始化是允许的:
ini
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
print(lineCount); //通过前面的逻辑判断可以这个lineCount是肯定能被赋值的。
4. 延迟初始化
在我们开发过程中,我们肯定会遇到很多需要声明全局变量,但是又不想声明为可空变量,也不想给特定的默认值,那改如何解决这个问题呢? late关键字可以帮我们解决这个问题。
ini
late String description;
void main() {
description = 'Feijoada!';
print(description);
}
如果使用了late这个关键字,在使用这个变量的时候,编译是不会去检查和推断你这个变量是否有初始化,一旦运行的时候发现它是未初始化的变量,则会报错。
5. 常量和不可变变量
常量也是我们日常开发中使用非常频繁的一个属性。那么在Dart中常见的两个关键字,一个是final,一个是const。那么他们分别有哪些使用场景和区别? final:通过关键字应该大致可以才到,和java其实很类似,就是一个运行时不可变的变量。 const:这个和final不太一样,这个属于编译时常量。 它们两者的区别其实和其它语言类似,编译和运行的时候,彼此所在的内存区和声明周期不一样。 普通的常见使用如:
ini
final name = 'Bob';
const nickname = 'Bobby';
这两个关键字不仅仅可以声明这种基础类型,还可以用来声明数组变量等。 如:
ini
final bar = [1,2,3,4];
const baz = [1,2,3,4];
这里有个点需要注意一下。那就是通过final声明点不可变变量是指针对变量本身不可被赋值,但是它的属性是可变的。如上声明的bar变量。如:
ini
bar = [2,2,2,2];//这个是会报错的,因为bar是被final修饰过的
bar[2] = 4;//这样是允许的,这行代码的意思就是给bar数组中下标为2的属性赋值4。执行完之后bar的值为[1,2,4,4]
而const声明的变量则不允许,const声明的数字是期变量本身以及内部的元素都是不可以变的。如:
ini
baz = [2,2,2,2]; //这个和final一样,都是不允许的
baz[2] = 4; // 这个和final不一样,final允许,但是const修饰的变量是不被允许的。
所以有一种场景,比如你想给某个主题声明一种色值。如:
csharp
const primaryColors = const [
const Color('red', const [255, 0, 0]),
const Color('green', const [0, 255, 0]),
const Color('blue', const [0, 0, 255]),
];
那这种场景const使用是有点冗余的。正确的使用应该是:
css
const primaryColors = [ Color('red', [255, 0, 0]),
Color('green', [0, 255, 0]),
Color('blue', [0, 0, 255]),
];
6. 可见性
Dart定义属性的私有和公有,和Java不太一样。是通过"_"前缀来区分的,如:
ini
class Person {
String _name = "Bob"; // 私有变量
String name = "Tony"; // 共有
}
但是Dart中的可见性没有Java中的那么严格,虽然在同一个文件中的不同类你把属性设置为私有,但是只要在同一个文件中都是可以访问的。如:
ini
class Pet {
String _name = "Kitte";
}
class Person {
void myPet() {
Pet pet = Pet();
print(pet._name);
}
}
但是如果在别的文件中去访问Pet的私有属性_name是访问不了的。