Flutter学习 第二天dart语法基础

这个转自我自己的有道云 想看图片去那里

文档:Day2_24 Dart语法.md
链接:http://note.youdao.com/noteshare?id=6c7875ef0d88c3e13440ccbec7d1e1b9&sub=55C6064F712D4B239B8D3FB7EDE5C5E0

Dart语法

认识Dart

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V81E4fVK-1582943518348)(452F75BF87FB4F5D951E4B66EBAAF821)]

安装dart

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPxvmPRf-1582943518349)(21A1E482D3754066ACD4C621151CCB95)]

其实可以

基础语法

每个语句以后必须打 分号

hello_dart.dart

print是重要的打印语句

main(List<String> args ){
    print("hello world");
}

args 是用终端调用的时候可以传的参数

  • 声明变量

注意变量的声明在dart里面有两种 一种是 明确的声明 另外一种是 类型推导

  1. 明确的声明

这点和java非常的相似

  String name = "why";
  print(name);
  1. 类型推导(var/final/const)

类型推导虽然没有指定变量的类型, 但是它是有类型的

这样编译器就会报错

main(List<String> args) {
  // 2. 类型推导
  var age = 20;
  age = "abc";
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qn4yZ4O5-1582943518350)(7E9BBAE3432E47E8B474E4BEEDB50437)]

2.1 但是如果确实希望像js一样使用我们可以使用dynamic (同时再涉及一下Object)

dynamic 本来的意思就是动态的

  dynamic age = 20;
  age = "abc";
  print(age);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R7vGvKli-1582943518350)(0BF83693CACD4613B3BDC00FAC2E9876)]

object 他是所有的对象的父类

但是像下面这样其实和dynameic 不一样 它原理其实因该更靠近 父类引用指向字类对象

  Object name = "why";
  // 这个toString 方法就是Object对象里面的
  print(name.toString());

上面这样是可以的

但是下面这样是不行的

  Object name1 = "why";
  // 父类引用指向字类对象 
  // 所以父类的引用肯定 肯定没有办法指向字类的方法
  print(name1.substring(1));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JoSEOXE8-1582943518351)(3D220CA8BB7D4833A3E7A066E97D3426)]

编译器说Object中没有定义这个substring的方法

但是dynamic 就可以实现这个功能

  // 但是dynameic 就可以实现这个功能
  dynamic name2 = "why";
  print(name2.substring(1));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XX9Ob1DP-1582943518351)(796711B788F142BEA091CE793A26FEBD)]

2.2 声明常量 final/const

声明一个常量只能在声明的时候赋值

main(List<String> args) {
  // 2.2 声明常量
  final height = 1.88;
  // height = 2.00; 不能改变常量的值
  // final weight; 这样初始化是不行的
  // weight = 20;
}

2.3 const 声明常量

同样是声明一个常量在声明的时候赋值

main(List<String> args) {
  // 2.3 const 声明常量
  const address = "广州市";
  // address = "test"; 同样不能改变它的值
}

2.4 const 和 final的区别

既然const 和 final的作用一样但是他们也是有区别的

  • const 必须赋值 常量值(编译期间需要有一个确定的值)
  • final 可以通过计算/函数获取一个值(运行期间来确定一个值)
  // 2.4 final 和 const 的区别 
  // const date1 = DateTime.now(); const  只能被赋值为常量的值 返回值是不行的
  final date1 = DateTime.now();
  print(date1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GE1syxEr-1582943518352)(97649220AB8C4EE3A3401C42299C7714)]

使用中还是final用的多一点, 因为它可以运行时被赋值

但是const 还是有用 它在创建这种重复使用的类的时候就可以节省内存(大概)

  // 2.5 用const 修饰构造函数
  // 这里是在生成对象 所以
  // dart 2.0 以后可以省略 new  创建对象时
  var p1 = Person1("why");
  var p2 = Person1("why");
  //  这个函数是用来判断两个对象是否相等
  print("identical(p1, p2)");
  print(identical(p1, p2));

  // 使用const 修饰的变量 如果传入的参数是相同的 他们的对象是相同的
  // 这个严格意义上不是单例 主要是为了节省内存 
  const p3 = Person2("why");
  const p4 = Person2("why");
  print("identical(p3, p4)");
  print(identical(p3, p4));
  
  class Person2 {
  final String name ;
  const Person2(this.name); 
  // 这里其实是初始化列表的使用方式
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MOBDE2YW-1582943518352)(71FA5F94652F4951934C056FB5B2386E)]

  1. dart 没有非零即真和非空即真

如果在判断的地方有空或者是0 编译器就会报错

main(List<String> args) {
  var flag = 0;
  if(flag) {
    print("这段话没有办法打印");
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x689sSRQ-1582943518353)(828603405E9644BE97649737674A6EAA)]

  • 4.数据类型

4.1 数字类型

对于数值来说我们也不用关心他是否有符号, 以及数据的宽度和精度等问题.只要记住整数用int , 浮点数用double就可以了

但是要注意一下, Dart中的 int和 double 可表示的范围并不是固定的, 它取决于运行Dart的平台

main(List<String> args) {
  // 1. int 类型
  int age = 18;
  int hexAge = 0x12;
  print(age);
  print(hexAge);

  // 2. 浮点类型double
  double height = 1.88;
  print(height);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAsYSTP4-1582943518353)(D170B1D9447F4747BC366C8A97C31D75)]

4.1.2 字符串和数值之间的转化

  // 1. 字符串转化成数值
  var one = int.parse("123");
  var two = double.parse("20.22");
  print("${one}, ${one.runtimeType}");
  print("${two}, ${two.runtimeType}");

  // 2. 数值转化成字符串
  var num1 = 123;
  var num2 = 123.456;
  var num1str = num1.toString();
  var num2str = num2.toString();
  var num2strD = num2.toStringAsFixed(2); // 保留两位小数
  print('${num1str}, ${num1str.runtimeType}');
  print('${num2str}, ${num2str.runtimeType}');

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXApG0bN-1582943518353)(AFF91050B9974901B587D073537BDEC8)]

4.2 布尔类型

  var isFlag = true;
  print("$isFlag ${isFlag.runtimeType}");
  if (isFlag ) {
    print("这段代码可以执行");
  } 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KLKSaFx4-1582943518354)(91C78133B07E4D71BFC1E051791AE86D)]

注意dart里面没有非零即真 也 没有非空即真

如果用了会报错

  var flag = "abc";
  if(flag) {
    print("这段代码不能执行");
  }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FTUce5C5-1582943518354)(2819973C38C8463E87E9FC8C65D2C5F7)]

4.3 字符串类型

Dart 字符串是UTF-16 编码的序列, 可以使用单引号和双引号

  var s1 = "Hello world";
  var s2 = 'Hello world';
  var s3 ="Hello\" world";
  var s4 = "Hello'Flutter";
  print(s1);
  print(s2);
  print(s3);
  print(s4);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GxvdG3rr-1582943518355)(E4ACA09339874AEB9C2811D4746D40AF)]

可以使用三个单引号或者双引号表示多行字符串

  // 2. 表示多行字符串的方式
  var message = '''
    test
    hahaha
    嘿嘿嘿
  ''';
  print(message);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWHetxhA-1582943518355)(9D8ED65C63934FA29D7389FA9D208B5E)]

4.4 集合类型

所谓集合就是数组啊对象啊这种数据的容器, 但是一般特指具有特殊数据结构的容器

对于集合类型, Dart则内置了最常用的三种: List / set / Map

List

其中List可以这样来定义 看着像数组

  // List的定义 列表List: []
  
  // 1. 使用类型推导定义
  var letters = ["a", "b", 123, 2.22, "d"];
  print('$letters, ${letters.runtimeType}');

  // 2. 明确指定类型
  List<int> numbers = [1, 2, 3, 4];
  print("$numbers, ${numbers.runtimeType}");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDvXyA1y-1582943518355)(CEF19E6AB7C8487CBA26239F4DB8A5C2)]

Set

其实set也是可以这样定义的

4.4.2.1 其实, 也就是把[]换成{}就好了
4.4.2.2 Set和List最大的不同就是: Set是无序的, 而且元素是不重复的

  // Set的定义 集合Set: {}
 // 1. 使用类型推导定义
 var lettersSet = {"a", "b", "c", 123};
 print("$lettersSet ${lettersSet.runtimeType}");

 // 2. 明确指定类型
 Set<int> numberSet = {1,2,3,4};
 print('$numberSet ${numberSet.runtimeType}');

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1TFe3bXd-1582943518356)(ACEB020D0DE543A889380EBFA94D363B)]

同时因为集合是不重复的, 所以我们可以通过这个性质来给数组去重

  // 因为集合是不重复的所以我们可以用这个方式来给数组去重
 List<String> movies = ["大话西游", "樱 恋萌芽", "大话西游", "变形金刚"];
 movies = Set<String>.from(movies).toList();
 print(movies);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3rz7RPO8-1582943518356)(F97D531439814845978660E62D819EB5)]

Map

最后Map是我们常说的字典类型 hash表

  // Map 的的定义
  // 1. 使用类型推导定义
  var infoMap1 = {"name": "why", 'age': 18};
  print("$infoMap1 ${infoMap1.runtimeType}");

  // 2. 明确指定类型
  Map<String, Object> infoMap2 = {"height": 1.88, "address": "北京市"};
  print("$infoMap2 ${infoMap2.runtimeType}");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sye7JZDR-1582943518357)(A19497603296436FA100CE91ED5B6BFE)]

4.4.2 集合的常见操作

了解这三个集合的定义方式以后,我们来看看最基础的公共操作

第一类, 是所有集合都支持的获取长度的属性length

  print(numbers.length);
  print(lettersSet.length);
  print(infoMap1.length);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWHbo1y3-1582943518357)(8DACC583CB6C4B0D946C07FE3849C31C)]

第二类 是添加 删除 包含

并且, 对于List来说, 忧郁元素是有序的, 它还提供了一个删除指定索引位置上元素的方法

  // 添加/删除/包含
  numbers.add(5);
  numberSet.add(5);
  print("$numbers $numberSet");

  numbers.remove(1);
  numberSet.remove(1);
  print("$numbers $numberSet");

  print(numbers.contains(2));
  print(numberSet.contains(2));

  // List根据index删除元素
  numbers.removeAt(3);
  print("$numbers");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ketxKnN3-1582943518357)(0E961932C2A34E3CBBF2399D10C4F290)]

第三类 是Map操作

由于它有key和value, 因此无论是读取值, 还是操作, 都要明确是基于key的, 还是基于value的, 或者是基于key/value 对(键值对)的

  // Map操作
  // 1. 根据key获取value
  print(infoMap1["name"]); // why

  // 2. 获取所有的entries
  print("${infoMap1.entries}       ${infoMap1.entries.runtimeType}");

  // 3. 获取所有的keys
  print("${infoMap1.keys}  ${infoMap1.keys.runtimeType}");

  // 4. 获取所欲的values
  print("${infoMap1.values}  ${infoMap1.values.runtimeType}");

  // 5. 判断是否包含某个key 或者values 
  print("${infoMap1.containsKey("age")}  ${infoMap1.containsValue(18)}");

  // 6. 根据key删除元素
  infoMap1.remove("age");
  print("$infoMap1");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWRqP7lU-1582943518358)(83FF46AD693148E6AD41D691646A60F0)]

  • 5.函数的基本定义

Dart 是一种真正的面向对象的语言, 所以即使是函数也是对象, 也有类型, 类型就是Function

函数的定义方式:

返回值类型 函数的名称(参数列表) {
    函数体
    return 返回值
}
main(List<String> args) {
  
}

int sum(int num1, int num2) {
  return num1 + num2;
}

同时我们是可以省略调返回值的

5.2 函数的参数问题

函数的参数分为两类: 必须参数和可选参数

5.2.1 可选参数

可选参数分为 命名可选参数 和 位置可选参数

定义方式

命名可选参数: {param1, param2}
位置可选参数: [param1, param2]

位置可选参数

位置可选参数 位置和参数类型必须对应

main(List<String> args) {
  // 如果sayHello(); 就会报错
  sayHello("输出的字符");

  sayHello1("输出的字符");
  sayHello1("输出的字符", 18);
}

// 这个地方参数是必须传的
// 不传编译器都会报错
void sayHello(String name) {
  print(name);
}

// 位置可选参数
// 意思是传是根据位置来的如果对应位置没有就不传
// 如果有的话就可以传 但是类型必须和位置对应 如果排在第二位是需要int类型 而传过来的第二位是字符串就会报错
void sayHello1(String name, [int age]) {
  print("$name $age");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aDves764-1582943518358)(CE2A2F122A9C4870A5DED7F1664AF311)]

命名可选参数

main(List<String> args) {
  sayHello2("输出的字符串", age: 18, height: 1.88);
  sayHello2("输出的字符串", height: 1.88);
  sayHello2("输出的字符串", age: 18);
}

// 位置可选参数
// 意思是传是根据位置来的如果对应位置没有就不传
// 如果有的话就可以传 但是类型必须和位置对应 如果排在第二位是需要int类型 而传过来的第二位是字符串就会报错
void sayHello1(String name, [int age]) {
  print("$name $age");
}

void  sayHello2(String name, {int age, double height}) {
  print("name = $name, age = $age, height = $height");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u9TPtdUX-1582943518359)(A9F8BBA5DFD84BD0BA192ABF6940912E)]

5.2.2 默认参数

main(List<String> args) {
  sayHello3("test");
  sayHello4("test");
}

void sayHello3(String name , {int age = 18, double height = 1.88}) {
  print("$name $age $height");
}

void sayHello4(String name, [int age = 18, double height = 1.88]) {
  print("$name $age $height");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOwmRzLJ-1582943518359)(02144215A10748AFBE6372E1225D2C9D)]

  • 函数是一等公民

在面向对象的语言中 类是一等公民

类(对象) 是第一等民 所以在各种以类作为第一公民(java/OC)的语言中 我们可以将类(对象)作为参数来传递

可以作为方法的参数, 也可以作为方法的返回值

但是在很多语言中, 函数并不能做为一等公民来使用, 这种限制让变成不够灵活, 所以现代编程语言基本都支持函数作为一等公民来使用, Dart也支持

这意味这两点

  1. 你可以将函数赋值给一个变量
  2. 也可以将函数作为一个函数的返回值来使用

具体来说就是

  1. 可以直接找到对应的函数名传进去
  2. 可以传任意函数 代参数的 不带参数
  3. 可以使用可以在去回调的函数里面写出回调函数的参数类型
  4. typedef 使用函数签名 说白了就是
  5. 可以将函数作为返回值
main(List<String> args) {
  // 1. 可以直接找到对应的函数名传进去
  test(bar);


  // 2. 可以传任意函数 代参数的 不带参数
  test(() {
    print("使用匿名函数");
  });
  // 箭头函数: 条件函数只有一行代码的时候才能使用
  test(() => print("使用匿名函数"));
  // 可以带参数 可以不带参数
  test(([int abc = 20]) {
    print("test");
  });

  // 3.  可以使用可以在去回调的函数里面写出回调函数的参数类型
  // 但是同时这种方式存在一个问题
  // 就是里面的函数作为参数变量太长不好看
  testWithFunctionParamters((age, height) {
    print("$age $height");
  });

  // 4. typedef 使用函数签名 说白了就是
  // 将调用回调函数的 参数 就是回调函数的类型
  // 作为一个标签保存起来 后面再用作 参数传进去
  test2((num1, num2) {
    return num1 + num2;
  });

  // 5. 可以将函数作为返回值
  print(demo()(20, 90));
}

void test(Function foo) {
  foo();
}

void bar() {
  print("我是bar函数");
}

void testWithFunctionParamters(void foo(int age, double height)) {
  foo(20, 1.88);
}

typedef Cal = int Function(int num1, int num2);
void test2(Cal calc) {
  print(calc(20, 30));
}

Cal demo() {
  return (num1, num2) {
    return num1 + num2;
  };
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KxercB70-1582943518359)(E1B6A1EA4A5F463FAE29854DE84BCC51)]

匿名函数

    () {
        print("这个是一个匿名函数");
    }

词法作用域

dart中有块级作用域

当内部作用域找不到时就会到外面去找, 这个和java很像

var name = "gobal";
main(List<String> args) {
//   (( ) {
//     print("这是一个匿名函数");
//   } )();
// }
  // var name = "main";
  void foo( ) {
    // var foo  = "foo";
    print(name);
  }

  foo();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CyCQ2g3V-1582943518359)(34A954B46DC24EBA8E31EB33029658F7)]

词法闭包

同样它有回调就有闭包

闭包可以访问其词法范围内的变量, 即使函数在其他的地方被使用, 也可以正常访问

  makeAdder(num addBy) {
    return (num i ) {
      return i + addBy;
    };
  }

  var addr2 = makeAdder(2);
  print(addr2(10));
  print(addr2(22));

  var addr3 = makeAdder(3);
  print(addr3(10));
  print(addr3(22));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hi1nd1Kz-1582943518360)(58FD0C0B0A204259A52DA343C33A54D6)]

  • 运算符

我们就说一些其他语言不常见的就可以了

??= 赋值操作

  1. 当变量为null时, 使用后面的内容进行赋值
  2. 当变量有值的时候, 使用自己原来的值
main(List<String> args) {
  var name1 = "coderwhy";
  name1  ??= "test";
  print(name1);

  var name2 = null;
  name2 ??= "test";
  print(name2);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1wo0apuj-1582943518360)(4D1CDB4CD72D4E8686B921193113204A)]

条件运算符 ??

  1. 如果expr1是null, 则返回expr2的结果
  2. 如果expr1不是null, 则直接使用expr1的结果

这个运算符吗在一些情况下和js的 || 作用相同

  var value1 = null;
  var value3 = "test";
  var value2 = "coder";
  print(value1 ?? value2);
  print(value3 ?? value2);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UHy3TI3K-1582943518360)(C023A5F83FA246CF9FC8BE8B7E1C9F9A)]

级联语法

为链式调用做准备

main(List<String> args) {
  var p1 = Person("coder", 19)
              ..eat()
              ..drink();
}
   
 class Person {
  String name;
  int age;

  Person(this.name, this.age);

  eat() {
    print("吃饭");
  }

  drink() {
    print("喝水");
  }
}               

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bx0O9My3-1582943518361)(AB0E91542F804C22BA14F6A33946BA3C)]

  • 流程控制

和大多数语言用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J9Fy8bqq-1582943518361)(2B05A756390044349FC229B4EBD381AC)]

同样是有迭代器的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dI3pmR51-1582943518361)(6A69B72D18074E34AFAF10AEA1DA2A86)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zdhK5ZQh-1582943518361)(63F0A5E057604A9B8BE92513753999EE)]

Dart 是一个面向对象的语言, 面向对象中的概念就是类, 类产生了对象.

这一节, 我们具体来学习类和对象, 但是Dart 对类进行了很多创新, 所以我们就要讲这部分的内容

3.2 类的构造方法

我们通过类创建一个对象的时候我们会使用构造方法

而Dart中

  1. 当类中没有明确指定的构造方法的时, 将默认拥有一个无参的构造方法
  2. 前面Person中我们就是调用这个构造方法
  3. 当我们自己定义了构造方法的时候原有的构造方法就会消失(同时注意Dart中式没有重载的)
  4. 我们可以重写父类的toString方法
main(List<String> args) {
  print(new Person("test", 12));
}

class Person {
  String name;
  int age;

  Person(String name, int age ) {
    this.name = name;
    this.age = age;
  } 

  @override
  String toString() {
    // TODO: implement toString
    return "name = $name, age = $age";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqi1abZ3-1582943518362)(40BE7C11203D4530AFE64B29E5698531)]

另外构造函数可以被简化

上面的构造方法可以优化成下面的

main(List<String> args) {
  print(Person1("test", 13));
}

class Person1 {
  String name;
  int age;
  
  Person1(this.name, this.age);

  @override
  String toString() {
    // TODO: implement toString
    return "name = $name, age = $age";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UlfvMVti-1582943518362)(16F9F95984F646E8AF1B1CA1B5DFA914)]

3.3 命名构造方法

因为在Dart 因为不支持函数的重载, 我们没有办法创建相同名称的构造方法

我们这个时候就可以使用命名构造函数

main(List<String> args) {
  print(new Person());
  print(new Person.withArgments("test", 12));
}

class Person{
  String name;
  int age;

  Person() {
    name = "";
    age = 0;
  }

  Person.withArgments(String name, int age) {
    this.name = name;
    this.age = age;
  }

  @override
  String toString() {
    // TODO: implement toString
    return "name = $name, age = $age";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKgUydMW-1582943518362)(F4BC2BFF3E5644A8A52A0FD7425A63B2)]

我们也可以通过命名构造函数, 提供更加快捷的对象的创建方式

  1. 比如开发中, 我们需要经常将一个Map对象转化成对象, 可以提供如下的构造方法
main(List<String> args) {
  print(new Person());
  print(new Person.withArgments("test", 12));
  print(new Person.withMapArgments({"name": "test2", "age": 123}));
}

class Person{
  String name;
  int age;

  Person() {
    name = "";
    age = 0;
  }

  Person.withArgments(String name, int age) {
    this.name = name;
    this.age = age;
  }

  Person.withMapArgments(Map<String, Object> map) {
    name = map["name"];
    age  =map["age"];
  }

  @override
  String toString() {
    // TODO: implement toString
    return "name = $name, age = $age";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQhIWeBT-1582943518363)(52FB6A2C40D34F7DA94CE6D07232B76E)]

3.2.3 初始化列表

我们来重新定义一个类Point, 传入, 可以得到他们的距离distance

import 'dart:math';

main(List<String> args) {
  var p1 = Point(2.0, 3.0);
  print(p1);
}

class Point {
  final num x;
  final num y;
  final num distance;

  // 错误的写法
  //  因为在执行下面的代码的时候对象的初始化已经完成了, 所以不能对它再进行赋值
  //  Point(this.x, this.y) {
  //    distance = sqrt( x * x + y * y);
  //  }

  // 正确的写法
  Point(this.x, this.y) : distance = sqrt(x * x + y * y);

  @override
  String toString() {
    // TODO: implement toString
    return "x  = $x, y = $y, distance = $distance";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2OYWCSlp-1582943518363)(6B1D671DC0924AB89BF44F77BFD3E8FD)]

我们可以通过初始化列表来初始化被 final 定义的属性

常量的构造方法更是需要, 初始化列表来为参数赋值

  // 2.5 用const 修饰构造函数
  // 这里是在生成对象 所以
  // dart 2.0 以后可以省略 new  创建对象时
  var p1 = Person1("why");
  var p2 = Person1("why");
  //  这个函数是用来判断两个对象是否相等
  print("identical(p1, p2)");
  print(identical(p1, p2));

  // 使用const 修饰的变量 如果传入的参数是相同的 他们的对象是相同的
  // 这个严格意义上不是单例 主要是为了节省内存 
  const p3 = Person2("why");
  const p4 = Person2("why");
  print("identical(p3, p4)");
  print(identical(p3, p4));
  
  class Person2 {
  final String name ;
  const Person2(this.name); 
  // 这里其实是初始化列表的使用方式
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fQN5tazy-1582943518363)(71FA5F94652F4951934C056FB5B2386E)]

3.2.4 在构造函数中调用另外的构造函数(重定向构造函数)

在某些情况下, 我们希望在一个构造方法中去调用另外一个构造方法, 这个时候我们可以使用重定向构造方法

main(List<String> args) {
  print( Person.fromName("test") );
}

class Person {
  String name;
  int age;

  Person(this.name, this.age);
  Person.fromName(String name) : this(name, 0);

  @override
  String toString() {
    // TODO: implement toString
    return "name = $name, age = $age";
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1jVbCKaw-1582943518364)(27C3F4EC23C446FBB0A291B3EAE413E8)]

3.2.5 常量构造方法

有些时候, 在传入相同的值的时候, 我们希望返回相同的对象, 这个时候我们可以使用常量构造方法, 创建对象的时候, 即使传入相同的参数, 创建出来的也不是同一个对象

但是如果我们使用常量构造函数, 我们就能得到传入相同的参数, 得到相同的对象

但是严格意义上我们这个东西不算是单例, 所以我们需要

main(List<String> args) {
  var p1 = Person("same");
  // 这个省略的是new 
  var p2 = new Person("same");
  // identical(a, b) 这个函数可以判断
  // a, b两个变量是否指向同一个对象
  print(identical(p1, p2));

  const p3 = Person2("same");
  // 这个省略的是const
  const p4 = const Person2("same");
  print(identical(p3, p4));
}

class Person {
  String name;

  Person(name) {
    this.name = name;
  } 
}

class Person2 {
  final String name;
  final int age;

  // const Person2(this.name);
  // 相当于 多个参数用逗号隔开
  const Person2(name) : this.name = name, this.age = 10;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5EKhTIPX-1582943518364)(062CF83DFF9B48FBA8347CAA4CD87BAD)]

3.2.6 工厂函数(单例模式)

Dart 提供了factory关键字, 用于通过工厂去获取对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值