final int number = 123;number = 233; // Error: Setter not found: 'number'.
const bool flag = true;flag = false; // Error: Setter not found: 'flag'.
var String str = 'abc';str = 'edg';
6. 默认值
如果在定义变量的时候没有初始化值,那么他的初始值是 null。除了常量,因为常量定义时必须有初始值
var some; // -> null
bool flag; // -> null
int number; // -> nullString str; // -> nullObject obj; // -> null
final namic; // Error: must be initialized
2. 数据类型
2.1 String
String str = 'abc';
模板字符串。使用方法与 js 一样
String name = '小明';
print('${name} 是个直男'); // -> 小明是个直男
多行字符串
与 js 的反引号不同,dart 需要使用三个单引号或双引号表示多行字符串
String breakStr = '''
这是一段,
多行字符串
2.2 numbers
数字类型有三种,int 、double 和 num
int 整形
int number = 123;
num = 1.1; // Error:不能将 double 类型的值赋值给 int 类型
double 浮点数
double number = 1.1;
number = 2; // Error: 不能将 int 类型的值赋值给 double 类型
int 与 doubled 都是 num 的子类,其相当于 int 与 double 的联合类型。
num number = 1;
number = 2.33; // 2.33
2.3 bool
与其他编程语言一样,她只有两个值。true or false
bool flag = 1 == 1;
print(flag); // -> true
与 js 不同的是,dart 在比较值的时候并不会对比较值自动进行类型转换
bool flag = 1 == '1';
print(flag); // -> false
dart 的 boolean 的显式的,只有 true 才会在判断时为 true
var flag = 1;
if(flag) {
print('真');
} else {
print('假');
// Error: 不能将 int 类型的值赋值为 bool 变量
classPerson{
String name = '汤姆';
int age = 8;
main() {
var tom = new Person();
print(tom.name); // '汤姆'
构造函数(constructor)
跟 js 不一样,dart 的构造函数是一个与 class 同名的函数。
classPerson{
String name;
int age;
// 与 class 同名的构造函数
Person(String name, int age){
this.name = name;
this.age = age;
void sayHi() {
print('my name is ${this.name}, 今年${this.age}岁');
main() {
Person xiaohong = new Person('小红', 8);
xiaohong.sayHi(); // -> my name is 小红, 今年8岁
构造函数不能被继承,但是子类会默认的去调用父类的没有参数的构造函数
classPerson {
String name;
Person(){
this.name = '我是谁';
classPeopleextendsPerson {
int age;
People() {
this.age = 18;
People xiaohong = newPerson();
print(xiaohong.name); // 默认调用了父类的构造函数,所以 name 属性有值print(xiaohong.age);
classPerson{
String name;
Person.name(String name) {
this.name = name;
// 构造函数 init 调用了构造函数 name
Person.init(String name): this.name(name);
sayHi() {
print('我叫$name');
main() {
Person xiaohong = new Person.init('小红');
xiaohong.sayHi(); // 我叫小红
工厂方法构造函数
如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义 这个构造函数。下面的类是为了创建 person 并避免创建重名的 person,创建新的对象后缓存起来,如果创建重名的就从已有的对象里面去取。
工厂方法构造函数里不能访问 this
classPerson{
String name;
staticfinalMap<String, Person> personMap = <String, Person>{};
factory Person(String name) {
if (personMap.containsKey(name)) {
print('catch person');
return personMap[name];
} else {
print('new person');
Person newPerson = new Person.create(name);
personMap[name] = newPerson;
return newPerson;
Person.create(String name) {
this.name = name;
sayHi() {
print('my name is ${name}');
main() {
Person xiaohong = new Person('小红'); // -> new person
xiaohong.sayHi(); // -> my name is 小红
Person xiaoming2 = new Person('小红'); // -> catch person
xiaoming2.sayHi(); // -> my name is 小红
上面创建的第二个小红,其实就是取得第一个小红,并没有创建新对象。
在 class 中访问 this 的成员的时候,可以忽略 this.xxx, 当未声明变量的时候会自动寻找 this 中有没有该属性
classPerson{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
void sayHi() {
// 这里手动定义的 age 优先级比 this.age 高var age = 99;
// 没有定义 name,会自动寻找 this.nameprint('my name is ${name}, 今年${age}岁');
main() {
var xiaohong = new Person('小红', 8);
xiaohong.sayHi(); // -> my name is 小红, 今年99岁
setters 与 getters
setters 与 getters 是用来设置与获取属性值的函数,一般情况下不需要手动设置,因为每个实例成员都有隐性的 getter 方法,非 final 的成员也会有隐性的 setter 方法。如果显式的去声明的话,使用 set 与 get 关键字
set 与 get 函数中都不可以访问自己,否则会死循环
set 函数中可以修改其他成员的值
下面的例子显式的声明了 Point 的 y 的 set 与 get 函数
classPoint{
int x;
Point(this.x);
intget y => x + 3;
set y(int value) => x = value;
main() {
Point point = new Point(5);
point.y = 10;
print(point.x);
print(point.y);
T getFirstItem<T>(List<T> arr) {
T firstItem = arr[0];
return firstItem;
var first = getFirstItem<int>([1, 2, '3']);
print(arr); // Error: 不能将参数类型 String 分配给 参数类型 int
上面代码因为 getFirstItem 在使用的时候声明泛型是 int,但是传入的 List 内却有 '4',所以报错了
extends
可以使用 extends 关键字来缩小泛型的类型范围,使用方式与 ts 一样
7. typedef
可以给方法的类型起个名字,用来定义方法的样子。类似于 ts 的 type,不过只能用于方法
typedefint Add(int x, int y);
main() {
Add add = (x, y) => x + y;
var sub1 = add(1, '2'); // Error: 不能将 String 类型的参数赋值给 int 类型的参数var sub2 = add(1, 2); // -> 3print(sub2 isint); // -> true
上面定义了一个名为Add的方法类型别名,其作为方法 add 的类型,因为 sub1 传入的参数类型与 Add 定义的不符,所以报错了。
因为 Add 定义了 add 方法的返回值是 int 类型,所以 (sub2 is int) 为 true
8. 模块化
7.1 pubspec.yaml
创建pubspec.yaml文件来声明该项目需要的依赖包,在 使用 put 命令拉取依赖包的时候会生成一个 .packages 文件,该文件将项目所依赖的每个程序包名称映射到系统缓存中的相应包