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<dynamic> 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<String, String>
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
//Map<int, String>
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
//Map<dynamic, String>
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 <extension name> on <type> {
(<member definition>)*
}
示例:
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中:
- class 就是 interface
- 当class被当做interface用时,class中的方法就是接口的方法,需要在子类里重新实现,在子类实现的时候要加@override
- 当class被当做interface用时,class中的成员变量也需要在子类里重新实现。在成员变量前加@override
- 实现接口可以有多个
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的功能,但是需要强调的是:
- mixins的对象是类
- mixins绝不是继承,也不是接口,而是一种全新的特性
- 可以mixins多个类
1.9.1、mixins的使用需要满足一定条件:
- mixins类只能继承自object
- mixins类不能有构造函数
- 一个类可以mixins多个mixins类
- 可以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中修饰的同名方法
- 自身的方法会覆盖其他所有修饰中的同名方法