二、Dart中方法、类、抽象类、接口、可调用类、混入、异常

2022-05-26  本文已影响0人  红鲤鱼与绿鲤鱼与驴与鱼
image.png

1、方法

1.1 一等方法对象

在dart 中是面向对象的编程 , num、String、dynamic、这些类型都是一个对象,当然也包括方法(Function)
看下面的代码, 先定义了一个fun() 方法 ,然后将方法赋值给 Function 变量, 再通过 变量 f 调用

//这是一个方法
void fun() {
  debugPrint("这是一个方法");
}

void main() {
  //方法都是对象,可以赋值给Function变量
  // Function 类,我们将 fun 方法赋值给Function 变量
  Function f = fun;
  //直接调用
  f();
}

上面的方法 fun() 是没有传参数的,如果我们想传参数应该怎么调用呢

//这个 参数是一个 Function对象(也就是说可以传入另一个方法,但是这里并没有指定方法的参数与返回值)
void fun(Function function) {
  debugPrint("这是 fun() 方法");
  //1、注意这个地方调用里面的参数是可以随便填的,因为我们并没有定义都有什么参数和方法的返回值
  function();
}

void main() {
  //方法都是对象,可以赋值给Function变量
  // Function 类,我们将 fun 方法赋值给Function 变量
  Function f = fun;
  //直接调用
  //2、传入一个匿名函数,这个传入的匿名函数也是可以随便传入参数的
  f((){
    debugPrint("这是参数方法");
  });
}
最后输出:
这是 fun() 方法
这是参数方法

注意这 1 和 2 的地方(匿名函数和被执行的函数),因为没有定义传入的方法参数和返回值,所以如果两边的参数不一致就会抛出异常(当然编译器是不会报错,只有在运行时才会报错)。 那么这个问题如何解决?
这就有了 typedef 关键字,它是用来定义一个类型的。看下面这行代码
typedef void F(String a,int b)
上面这段代码的意思是:定义了一个 F 的类型,这个F的类型其实就是一个方法, 参数(String,int) 返回值void

//定义了一个F类型,F 类型其实就是一个方法,参数是(String,int) 返回值是 Void
typedef void F(String a, int b);

//定义一个方法,些方法的参数 是一个 F 类型
void fun2(F function) {
  debugPrint("这是 fun2() 方法");
  //因为它是一个F类型,所以在调用的时候要按照我们定义的方法去传参数,而不是和上面一样随便传参
  function("abc", 2);
}

void main() {
  Function f2 = fun2;
  //调用 fun2() 方法,并且传入匿名函数(这里的参数必须要和上面定义的F类型一样)
  f2((String a, int b) {
    debugPrint("这是 Fun2 方法 $a $b");
  });
}

当然除了上面这种还有其他的写法,这三种用哪个都行,个人喜欢上面那个

//直接定义在方法上也是可以的
void fun3(void Function(String str, int a) function) {
  function("fun3", 123);
}
//这两个方法是一样的
void fun4(void function(String str, int a)) {
  function("fun4", 123);
}
1.2 可选位置参数

在Dart中有一些参数是可选得,调用方法的时候即使不传也是可以的
注意可选位置参数是 有顺序的,如果你想给第二个参数传值,那么前面的必须也要传

//可选位置参数,可以设置默认参数
void fun([int? a, int? b = 2]) {
  debugPrint("$a");
  debugPrint("$b");
}

void main() {
  //这是给第一个参数传值
  fun(10);
  //如果想给第二个参数传就必须保证前面的参数有值
  fun(20,22);

}
1.3 可选命名参数

调用命名参数时必须要有形参的变量名,而且有了名字就不用在意位置了。不管是命名参数还是位置参数都是可以设置默认值的


//可选命名参数
void fun2({int i = 1, j = 2}) {
  debugPrint("i=$i;j=$j");
}

  //调用命名参数时必须要有形参的变量名,而且有了名字就不用在意位置了
  fun2(j: 47);
  fun2(i: 35, j: 28);
  fun2(j: 98, i: 73);

2、类

所有的类都继承Object

2.1 变量

在Dart中是没有 private 关键字的, 如果想让一个变量是私有的使用 _ 开头的命名

class Point {
  //私有变量
  final String _a = "abc";
  int b = 123;
}
2.2 构造方法
//类的定义
class Person {
  // late 关键字表示 延迟初始化,和Kotlin中 lateinit 一个道理
  late String name;
  late int age;

  //标准的构造函数
  Person(this.name, this.age);

  //在Dart中未命名的构造只能有一个,可以有无数个命名的构造
  Person._() {
    name = "";
    age = 0;
  }
  //命名构造
  Person.a();
}
2.3 初始化列表

主要功能就是初始化参数,当然也是可以在构造的方法体中进行初始化的

class Point {
  String? _a = "abc";
  int b = 123;
  //命名构造
  Point.Map(Map<String, String> map) : _a = map["a"];//初始化参数列表
  void printA() {
    debugPrint("_a:$_a");
  }
}

void main() {
  Map<String, String> map = {"a": "aah"};
  var p1 = Point.Map(map);
  p1.printA();
}
2.4 常量构造函数

在Dart中有两个常量的关键字 const 和 final

class MyPoint {
  final int x;
  final int y;
//常量构造函数
  const MyPoint(this.x, this.y);
}

void main() {
  var p1 = const MyPoint(1, 2);
  var p2 = const MyPoint(1, 2);
  var p3 = const MyPoint(1, 3);
  debugPrint("${p1 == p2}"); // 输出结果为true,注意这两个的参数是一样的,如果不一样就为false
  debugPrint("${p2 == p3}");//参数不一样为false
}

常量构造函数在其他语言中是没有的。在Dart中是很常见的,这是因为在Dart中控件都可以是一个类.比如我们在不同页面中有三个TextView 显示的内容是一样的,那如果使用常量构造函数创建出来的组件就是同一个对象,而不会产生三个对象

2.5 工厂构造函数 与 静态方法

工厂构造函数 的关键字是 factory. 必须要有一个构造函数

class Manager {
  late int i;
  //普通函数
  Manager();
  //工厂构造函数
  factory Manager.get() {
    //调用未命名的构造(但是这个构造必须也要有)
    return Manager();
  }
}
//继承
class Child extends Manager {}

在Dart中静态方法使用 static ,静态方法可以直接使用 类名.方法名() 调用

class C {
  static print(obj) {
    debugPrint("$obj");
  }
}

//调用
void main() {  
  //通过类名直接调用  
  C.print(test);
}
2.6 Getter 与 Setter 方法

Dart 语言中的这两个方法都是有对应的 getset 关键字。
get 方法是没有参数列表的,所以不需要 加括号
set 方法必须要声明一个参数

class Child extends Manager {
  int _x = 0;

  Child() : super();

  int get getX {
    return _x;
  }

  set setX(int a) {
    _x = a;
  }
}

这里当我们调用 set 方法时更像是给变量赋值

  var child = Child();
  child.setX = 1;
  // child.setX(1); 这样写会报错
2.7 操作符重载

在Kotlin中也有这个功能, 这两个语言使用的关键字是一样的

class Child  {
  int _x = 0;
 
  int get getX {
    return _x;
  }

  set setX(int a) {
    _x = a;
  }
  //返回值和参数可以定义成任何自己需要的类型
  int operator +(Child c) {
    var child = Child();
    child.setX = _x + c.getX;
    return child.getX;
  }}

调用的时候需要注意前面的是调用者后面的是参数

  var child = Child();
  child.setX = 3;
  var child2 = Child();
  child2.setX = 4;
//这里 child 是调用者,child2 是参数,相当于 child.+(child2)
int c = child + child2;
  debugPrint("${c}");

下面这个图片是可重载的操作符


可重载的操作符.png

3 、抽象类与接口

3.1 抽象类
abstract class A {
  //构造方法本身可以省略方法体
  A();

  //在抽象类中没有方法体的就是抽象方法
  void test();

  //有方法体的是实例方法
  void test2() {
    debugPrint("这是 实例方法 test2()");
  }
}

class B extends A {
  @override
  void test() {
    // TODO: implement test
  }
}
3.2 接口
//创建一个普通的类 Test
class Test {
 //变量
  int x = 0;
 
 //方法
  void fun1() {}
}

//实现 Test 类
class MyTest implements Test {

  @override
  late int x = 1;
  
  @override
  void fun1() {
    // TODO: implement fun1
  }
}

4、可调用的类

如果一个类中有 call() 方法,可直接调用,代码如下

class MyTest  {
 
//  可调用的类
  void call() {
    debugPrint("Call 方法");
  }
}

void main() {
  var test = MyTest();
  //直接调用call
  test();
  //平时这样调用也是可以的
  test.call();
}

5、混合 mixins

混合类似是多继承,可以把多个类中的方法混入到新的类中
如下代码,将A,B混入到C类中

class A{
  void a(){
    debugPrint("A类的 a() 方法");
  }
  void b(){
    debugPrint("A类的 b() 方法");
  }
}

class B{
  void b(){
    debugPrint("B类的 b() 方法");
  }
}

//将A,B混入到C类中
//注意混入的顺序
class C with A,B{
  @override
  void a(){
    debugPrint("C类的 a() 方法");
  }
}
//如果C类中没有自己的方法的话还可以使用下面的语法糖
class C = Object with A, B;

注意:

6、异常

上面记录了一些类相关的知识,接下来记录一下异常相关
在Dart中可以抛出任何类型的异常,包括但不限于 int String bool Function
对,你没有看错还可以抛出一个方法

//这里的index 动态的数据类型 dynamic
void _throwException(index){
  if (index == 0) {
    throw "字符串";
  } else if (index == 1) {
    throw 100;
  } else if (index == "2") {
    throw print;
  }
}


void test(){
  print("======");
  try{
    _throwException("2");
//使用 on 判断 是哪种异常
  }on int catch(e,s){
    print(e);
    print(e.runtimeType);
   }on String catch(e,s){
    print(e);
    print(e.runtimeType);
   }on Function catch(e){
    e("这是一个方法");
    e(e.runtimeType);
  }
}
上一篇下一篇

猜你喜欢

热点阅读