Dart语言基础

1.1、基本数据类型

1.1.1、Number

Dart 语言的 Number 有两种类型:

int: 整数值不大于64位, 具体取决于平台

double: 64位(双精度)浮点数

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

1.1.2、String

Dart 字符串是一组 UTF-16 单元序列。 字符串通过单引号或者双引号创建。

 var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

字符串可以通过 ${expression} 的方式内嵌表达式。 如果表达式是一个标识符,则 {} 可以省略。 在 Dart 中通过调用就对象的toString() 方法来得到对象相应的字符串。可以使用 + 运算符来把多个字符串连接为一个,使用连续三个单引号或者三个双引号实现多行字符串对象的创建

var name = 'dart';
var s1 = 's is $name';
var s2= 's is $name' + 'language';
var s3 = '''
You can create
multi-line strings like this one.
''';

1.1.3、Boolean

Dart 使用 bool 类型表示布尔值。 Dart 只有字面量 true and false 是布尔类型

1.1.4、List

var list = [1, 2, 3];
List list2 = [1, 2, 3,'ss']; //List list2 = [1, 2, 3,'ss'];
list2.remove(2);
list2.clear();
list2.add(2);
list2.addAll(['a', 'b']);

1.1.5、Map

Map 是用来关联 keys 和 values 的对象。 keys 和 values 可以是任何类型的对象。

//Map 
var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

//Map 
var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

//Map 
Map nobles = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
  'name' : 'dart',
};

1.2、变量

  • 任何保存在变量中的都是一个 对象 , 并且所有的对象都是对应一个 的实例。 无论是数字,函数和 null 都是对象。所有对象继承自 Object 类。
  • 使用过程中从来不会被修改的变量, 可以使用 final 或 const, 可被修改的变量是 var 或者其他类型, Final 变量的值只能被设置一次; Const 变量在编译时就已经固定
var name = 'Bob';
String name2 = "Bob";

final name3 = 'name3';
// final String name3 = 'name3';
// name3 = "pop"; //The final variable 'name3' can only be set once.

const name4 = 'name4';
// name4 = "pop"; //Constant variables can't be assigned a value.

final name5;
name5 = "name5";
// name5 = 'pop'; //The final variable 'name5' can only be set once.

// const name6; //The constant 'name6' must be initialized.

1.3、构造函数

1.3.1、默认构造函数

类里面没有显示写构造函数,默认是一个隐式的无参构造函数

1.3.2、 普通构造函数

指定一个类名相同的方法就是普通构造函数

class Test{
  int a, b;
  Test(int a, int b){
    this.a = a;
    this.b = b;
  }
}

可以将上述直接简写为

class Test{
  int a, b;
  Test(this.a, this.b);
}

1.3.3、 命名构造函数

命名构造函数就是给构造函数添加个名字,使用命名构造函数可为一个类实现多个构造函数, 也可以使用命名构造函数来更清晰的表明函数意图:,比如从json转model时常用的fromJson就是命名构造函数, 命名构造函数不可以继承

class Test{
  int a, b;
  Test(this.a, this.b);
  
  Test.fromJson(int a, int b){
    this.a = a;
    this.b = b;
  }
  
  //同样可以简写
  //Test.fromJson(this.a, this.b);
}

1.4 、可选参数

函数有两种参数类型: required 和 optional。 required 类型参数在参数最前面, 随后是 optional 类型参数。可选参数可以是命名参数或者位置参数,但一个参数只能选择其中一种方式修饰。

1.4.1、命名可选参数

定义函数时,使用 {param1, param2, …} 来指定命名参数,默认都是可选如:

void enableFlags({bool bold, bool hidden}) {...}

使用 @required 注释表示参数是 required 性质的命名参数如:

 Scrollbar({Key key, @required Widget child})

1.4.2、位置可选参数

将参数放到 [] 中来标记参数是可选的如:

String say(String from, String msg, [String device]) { 
  var result = '$from says $msg';  
 if (device != null) {
     result = '$result with a $device';   
    }  
 return result;
}

String result = say('Bob', 'Howdy');

1.4.3、默认参数值

在定义方法的时候,可以使用 = 来定义可选参数的默认值。 默认值只能是编译时常量。 如果没有提供默认值,则默认值为 null。

//命名可选参数 
void nameFlags(String name, int age,
        {bool bold = false, int height = 180}) {
      print(name + '$age' + '$bold' + '$height');
        //name18false190

    }
  nameFlags('name', 18, height: 190);

//位置可选参数
void enableFlags(String name, int age,
        [bool bold = false, int height = 180]) {
      print(name + '$age' + '$bold' + '$height');
         //pop18true180
    }

// bold 值为 true; 
    enableFlags('pop', 18, true);

1.5、抽象类用abstract关键字

  • dart抽象类主要用于定义标准, 子类可以继承抽象类,也可以实现抽象类接口
  • Dart中抽象方法不能用abstract来修饰, Dart中没有方法体的方法称为抽象方法
  • 如果子类继承抽象类,那么必须要实现抽象类里的抽象方法

抽象类用途: 抽象类主要用于约束子类 比如子类Dog中必须实现eat和run这两个方法 这个时候父类就要用abstract来修饰(定义标准)

abstract class Animal {
  eat(); // 抽象方法 因为没有方法体
  run();

  printInfo() {// 普通方法 因为有方法体
    print('我是抽象类里的一个普通方法');
  }
}

class Dog extends Animal {
  @override
  eat() {
    // TODO: implement eat
    print('小狗在吃狗粮');
  }

  @override
  run() {
    // TODO: implement run
    print('小狗在跑');
  }
}

1.6、继承

  • 用extends来继承其他类
  • 子类会继承父类里面可见的属性和方法 但是不会继承构造函数
  • 子类能复写父类的方法
  • 如果父类的默认构造函数 为有参数的构造函数 则子类必须要写自己的构造函数
  • 重写父类方法 直接和父类重名就行了或者用 @override
  • @override 可以写 也可以不写 建议写上
  • 子类里调用父类的方法 用super
class Person {
  String name = '张三';
  int age = 23;

  void getInfo() {
    // print("姓名:$name ----- 年龄:$age");
    print('姓名:${this.name}----- 年龄:${this.age}');
    // this关键字指向了当前类的实例
  }
}

子类

class Boy extends Person {
  String sex = 'man';
  // 如果父类的默认构造函数 为有参数的构造函数 则子类必须要写自己的构造函数
  Boy(String name, int age, String sex) : super(name, age) { 
  // super 表示  把子类初始化时传进来的参数 赋值给父类
     this.sex = sex;
  }

  @override  // @override 可以写 也可以不写 建议写上
  void getInfo() {
    // TODO: implement getInfo
    // super.getInfo();
    print('复写父类 ${this.name}-----${this.age}');
  } 
}

1.7、extension之扩展方法

Dart 扩展需要关键词:extension。这个关键字只有在 Dart 版本 2.7 及其以上才支持。所以请确保你工程项目中 pubspec.yaml 文件中:

environment:
sdk: ">=2.7.0 <3.0.0"

extension 的用法:

extension  on  {
  ()*
}

示例:

extension StringExtension1 on String {
  //字符转换成Color对象
  toColor() {
    var hexColor = this.replaceAll("#", "");
    if (hexColor.length == 6) {
      hexColor = "FF" + hexColor;
    }
    if (hexColor.length == 8) {
      return Color(int.parse("0x$hexColor"));
    }
  }

  //字符转int
  parseInt() {
    return int.parse(this);
  }
}

extension DateTimeExtension on DateTime {
  toFormatString() {
    DateFormat dateFormat = new DateFormat("yyyy-MM-dd HH:mm:ss");
    return dateFormat.format(this);
  }
}

扩展不仅可以定义方法,还可以定义,setter,getter,operator。如果要使用这些扩展方法,只要引用导入对应的 dart 文件即可。

import 'util/extensions.dart';//导入

void main() {
  print("#90F7EC".toColor());
  print("23".parseInt());
}

1.8、接口 用关键词implements实现

Flutter是没有interface的,但是Flutter中的每个类都是一个隐式的接口,这个接口包含类里的所有成员变量,以及定义的方法。如果有一个类 A,你想让类B拥有A的API,但又不想拥有A里的实现,那么你就应该把A当做接口,类B implements 类A.

所以在Flutter中:

  1. class 就是 interface
  2. 当class被当做interface用时,class中的方法就是接口的方法,需要在子类里重新实现,在子类实现的时候要加@override
  3. 当class被当做interface用时,class中的成员变量也需要在子类里重新实现。在成员变量前加@override
  4. 实现接口可以有多个
abstract class A {
  late String name;
  printA();
}

abstract class B {
  printB(){

  }
}

class C implements A,B{
  @override
  late String name;

  @override
  printA() {
    // TODO: implement printA
    throw UnimplementedError();
  }

  @override
  printB() {
    // TODO: implement printB
    throw UnimplementedError();
  }
  
}

1.9、混合 mixins (with)

mixins的中文意思是混入,就是在类中混入其他功能。mixins是要通过非继承的方式来复用类中的代码。举个例子,有一个类A,A中有一个方法a(),还有一个类B,也想使用a()方法,而且不能用继承,那么这时候就需要用到mixins,类A就是mixins类(混入类,),类B就是要被mixins的类,对应的Dart代码如下:

void main() {
  B b = new B();
  print(b.content);
  b.a();
}

class A {
  String content = 'A Class';

  void a() {
    print("a");
  }
}

class B with A {}

输出是:

A Class
a

将类A mixins 到 B,B可以使用A的属性和方法,B就具备了A的功能,但是需要强调的是:

  1. mixins的对象是类
  2. mixins绝不是继承,也不是接口,而是一种全新的特性
  3. 可以mixins多个类

1.9.1、mixins的使用需要满足一定条件:

  1. mixins类只能继承自object
  2. mixins类不能有构造函数
  3. 一个类可以mixins多个mixins类
  4. 可以mixins多个类,不破坏Flutter的单继承

1.9.2、on关键字

on只能用于被mixins标记的类,例如mixins X on A,意思是要mixins X的话,得先接口实现或者继承A。这里A可以是类,也可以是接口,但是在mixins的时候用法有区别.

class A {
  void a() {
    print("a");
  }
}

class B {
  void b() {}
}

mixin X on A {
  void x() {
    print("x");
  }
}

// on 一个类(把A作为一个类)
// 用继承:
class mixinsX extends A with X {}

// on 的是一个接口(把A作为接口):
// 得首先实现这个接口,然后再用mix

class implA implements A {
  @override
  void a() {
    // TODO: implement a
  }
}

class mixinsX2 extends implA with X {}


//'X' can't be mixed onto 'Object' because 'Object' doesn't implement 'A'.
// class minxsBX extends B with X{
   
// }

1.10、方法冲突

如果同时存在extends, with,implements,并且它们都定义了相同的方法名,就会存在方法冲突,我们来看下面的例子:

class Extends {
  
  void log() {
    print('extends');
  }
  
}

mixin Mixins {
  
  void log() {
    print('mixin');
  }
  
}

mixin Mixins2 {
  
  void log() {
    print('mixin2');
  }
  
}

class Log extends Extends with Mixins, Mixins2 {}

void main() {
  Log().log();
}

输出结果

mixin2

再来看一下加上了implements的情况:

class Extends {
  
  void log() {
    print('extends');
  }
  
}

mixin Mixins {
  
  void log() {
    print('mixin');
  }
  
}

mixin Mixins2 {
  
  void log() {
    print('mixin2');
  }
  
}

class Implements {
  
  void log() {
    print('implements');
  }
  
}

class Log extends Extends with Mixins, Mixins2 implements Implements {}

void main() {
  Log().log();
}

输出结果为:

mixin2

这是因为在这种情况下,它识别到我们从with和extends中获得了log()方法的能力,因此调用的是Mixins2.log()。

假如我们对Implements#log方法进行实现:

class Log extends Extends with Mixins, Mixins2 implements Implements {
  
  void log() {
    print("log log");
  }
}

输出的结果为:

log log

结论:

  • with修饰的会覆盖extends中修饰的同名方法。
  • with列表中后一个的会覆盖之前的。
  • extends 修饰的会覆盖implements中修饰的同名方法
  • 自身的方法会覆盖其他所有修饰中的同名方法

你可能感兴趣的:(Dart语言基础)