Flutter/Dart第15天:Dart类结构函数
Dart官方文档:https://dart.dev/language/constructors
重要说明:本博客依据Dart官网文档,但并不是简略的对官网进行翻译,在掩盖中心功用情况下,我会依据个人研制经历,参加自己的一些扩展问题和场景验证。
如下代码样例,和Java相似,最常用的生成式结构函数:
class Point {
double x = 0;
double y = 0;
Point(double x, double y) {
this.x = x;
this.y = y;
}
}
最佳实战:在Dart中,仅当命名抵触时,才运用this关键字,不然一般能够省掉this
关键字。
初始化参数列表
如上最常用的结构函数,Dart能够进一步优化如下初始化参数方式。一同,也能够为非空变量设置默许值。
class Point {
final double x;
final double y;
// 在结构函数体履行之前,初始化实例变量
Point(this.x, this.y);
}
默许结构函数
和Java相似,类假如没有声明结构函数,那么它会有个默许的结构函数。默许结构函数没有入参,它只会调用父类的没有入参的结构函数。
结构函数无法承继
子类无法承继父类的结构函数,假如子类没有声明结构函数,那么这个子类就只有默许结构函数(不管父类是否有其他结构函数)。
命名结构函数
在Dart中,经过命名结构函数,能够为类供给多个结构函数,并且在创立目标时愈加明晰。
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
Point(this.x, this.y);
// `origin`命名结构函数
Point.origin()
: x = xOrigin,
y = yOrigin;
}
特别注意:如上节说到,子类无法承继父类的结构函数,包含父类的命名结构函数。假如子类想运用父类的某个命名结构函数,那么子类有必要完成该命名结构函数。
调用父类结构函数
默许情况下,子类无入参的非命名结构函数会调用父类的无入参的非命名结构函数。父类的结构函数在结构函数体之前被调用。假如有初始化参数列表,那么初始化参数列表在父类结构函数调用之前被调用。
结构函数相关的调用次序如下:
- 初始化参数列表
- 父类无入参的结构函数
- 子类无入参的结构函数
特别注意:假如父类没有经过无入参且非命名的结构函数,那么咱们有必要手艺调用父类的一个结构函数,经过冒号:
后边紧跟父类结构函数。
如下代码样例,Person
是父类,它仅声明晰一个命名结构参数。Employee
是承继Person
的子类,由于父类没有声明无入参非命名的结构函数,因而在它结构函数都有必要手艺调用父类的某个结构函数。如命名结构函数fromJson
后边,经过冒号:
调用了父类的命名结构函数。
// 未声明:无入参、非命名的结构函数
class Person {
String? firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// 手艺调用父类的结构函数:super.fromJson()
Employee.fromJson(super.data) : super.fromJson() {
print('in Employee');
}
}
void main() {
var employee = Employee.fromJson({});
print(employee);
// 成果:
// in Person
// in Employee
// Instance of 'Employee'
}
特别注意:由于结构函数参数是在调用结构函数之前核算,因而结构函数的参数能够是表达式,如函数调用等。父类的结构函数不能运用this.
关键字,由于参数能够是表达式、静态函数等,并不一定是类实例。
class Employee extends Person {
Employee() : super.fromJson(fetchDefaultData());
// ···
}
手艺调用父类的结构函数,然后逐个设置入参比较繁琐,假如咱们想要简化,那么能够父类的初始值结构函数。这个功用不能与重定向结构函数一同运用(由于语法抵触)。
class Vector2d {
final double x;
final double y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// 默许情况下,咱们的运用方法:
// Vector3d(final double x, final double y, this.z) : super(x, y);
// 简化版别:
Vector3d(super.x, super.y, this.z);
}
如下代码样例,父类的初始化结构函数能够经过命名参数调用。
class Vector2d {
// ...
Vector2d.named({required this.x, required this.y});
}
class Vector3d extends Vector2d {
// ...
Vector3d.yzPlane({required super.y, required this.z}) : super.named(x: 0);
// 等价调用
// Vector3d.yzPlane({required double y, required this.z}) : super.named(x: 0, y: y);
}
初始化列表
在结构函数履行之前,咱们能够调用父类的结构函数,还能够初始化实例变量。实例变量初始化经过逗号分隔。
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']! {
print('In Point.fromJson(): ($x, $y)');
}
开发阶段,咱们能够在初始化列表中添加断语:
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
初始化列表在设置final
不行变量时十分有用:
import 'dart:math';
class Point {
final double x;
final double y;
final double distanceFromOrigin;
Point(double x, double y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
void main() {
var p = Point(2, 3);
print(p.distanceFromOrigin);
// 输出:3.605551275463989
}
重定向结构函数
重定向结构函数,便是运用类的其他的结构函数,重定向到的结构函数运用this
关键字:
class Point {
double x, y;
// 主结构函数
Point(this.x, this.y);
// 重定向到主结构函数
Point.alongXAxis(double x) : this(x, 0);
}
常量结构函数
假如目标的数据不会改动,这些目标能够作为编译期常量。
常量结构函数要求:实例变量都是final
不行变量,界说一个const
修饰符的结构函数。
特别注意:上一文咱们有说到常量结构函数,常量结构函数创立的目标并不一定<?都是常量(当创立的目标没有const
修饰符,或许目标不是在const
常量上下文中,那么该目标就不是常量)!
如下代码样例,ImmutablePoint
有常量结构函数,它创立的3个目标中,前面2个是常量,后边1个并十分量。
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
// `a`和`b`目标是常量,且它们归于同一个实例
var a = const ImmutablePoint(1, 2);
var b = const ImmutablePoint(1, 2);
assert(identical(a, b));
// `c`目标并十分量,它也和`a`或许`b`不是同一个实例
var c = ImmutablePoint(1, 2);
assert(!identical(a, b));
工厂结构函数
在一个不总是创立实例的类中,运用factory
关键字完成一个结构函数,即为工厂结构函数。
工厂结构函数常用运用场景:如经过结构函数,从缓存获取目标,或许创立其子类,或许创立不行变常量可是又不想供给初始化参数列表等。
如下代码样例,Logger
工厂结构函数优先从缓存获取目标,而Logger.fromJson()
工厂结构函数则初始化了一个final
不行实例变量:
class Logger {
final String name;
bool mute = false;
static final Map<String, Logger> _cache = <String, Logger>{};
// 优先从缓存获取目标,假如不存在则新增
factory Logger(String name) {
print('默许结构函数:$name');
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// 命名结构函数,经过工厂结构函数获取目标(缓存,或新增)
factory Logger.fromJson(Map<String, Object> json) {
print('命名结构函数:$json');
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
工厂结构函数的运用,和一般结构函数无本质区别:
var logger = Logger('UI');
logger.log('Hi NTopicCN.');
// 成果:
// 默许结构函数:UI
// Hi NTopicCN.
var loggerJson = Logger.fromJson({'name': 'UI'});
loggerJson.log('Hello Logger.');
// 成果:
// 命名结构函数:{name: UI}
// 默许结构函数:UI
// Hello Logger.
我的本博客原地址:https://ntopic.cn/p/2023102101