Finalizable抽象 接口

不应过早终止的对象的标记接口。

任何具有静态类型包含 Finalizable 的局部变量都保证在执行退出变量作用域的代码块之前保持存活。

一个类型包含 Finalizable,如果以下条件之一成立:

  • 类型是非 Never 子类型 Finalizable,或
  • 类型是 T?FutureOr<T>,其中 T 包含 Finalizable

换句话说,当对象通过此类变量引用时,保证它不会被视为不可达,并且变量本身在其作用域内的整个持续时间都被视为存活,即使它在最后一次引用之后。

如果没有在变量的类型上使用此标记接口,变量的值可能在完全执行周围作用域之前被垃圾回收,只要变量肯定不再被引用。这反过来可能会触发 NativeFinalizer 执行回调。当变量的类型包含 Finalizable 时,直到当前使用该变量的代码完成,才会阻止 NativeFinalizer 回调运行。

例如,在执行 someNativeCall 期间,finalizable 保持存活。

void myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  someNativeCall(finalizable.nativeResource);
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

实现 Finalizable 的类的 this 对象在方法执行期间保持存活。this 值被处理为局部变量。

例如,在 myFunction 中执行 someNativeCall 期间,this 保持存活。

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);

  void myFunction() {
    someNativeCall(nativeResource);
  }
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

将涉及可终止类的逻辑实现为实现 Finalizable 的类的函数是一种好的实践。

如果在声明变量的块作用域内部创建闭包,并且该闭包包含对变量的任何引用,则变量在闭包对象保持存活或闭包体执行期间保持存活。

例如,finalizable 由闭包对象保持存活,直到闭包体的末尾。

void doSomething() {
  final resourceAction = myFunction();
  resourceAction(); // `finalizable` is alive until this call returns.
}

void Function() myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  return () {
    someNativeCall(finalizable.nativeResource);
  };
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

只有捕获的变量才由闭包保持存活,而不是所有变量。

例如,finalizable 不由返回的闭包对象保持存活。

void Function() myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  final nativeResource = finalizable.nativeResource;
  return () {
    someNativeCall(nativeResource);
  };
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

如果从可终止对象中提取的资源逃离了从其提取的可终止变量的作用域,则可能是一个错误。

Finalizable 变量的行为也适用于异步函数。此类变量在声明变量的作用域内或捕获变量的闭包中保持存活,只要在该执行期间可能执行任何代码,即使存在异步延迟。

例如,在执行 await someAsyncCall() 期间,finalizable 保持存活。

Future<void> myFunction() async {
  final finalizable = MyFinalizable();
  await someAsyncCall();
}

Future<void> someAsyncCall() async {
  // ..
}

class MyFinalizable implements Finalizable {
  // ..
}

在异步代码中,如果从可终止对象中提取的资源逃离了从其提取的可终止变量的作用域,则可能是一个错误。如果您必须从 Finalizable 提取资源,请确保通过 await 任何使用该资源的异步代码的作用域,使定义 Finalizable 的作用域比资源长。

例如,在 useAsync1 中,this 保持存活,直到 resourceuseAsync1 中不再使用,但在 useAsync2useAsync3 中则不是。

class MyFinalizable {
  final Pointer<Int8> resource;

  MyFinalizable(this.resource);

  Future<int> useAsync1() async {
    return await useResource(resource);
  }

  Future<int> useAsync2() async {
    return useResource(resource);
  }

  Future<int> useAsync3() {
    return useResource(resource);
  }
}

/// Does not use [resource] after the returned future completes.
Future<int> useResource(Pointer<Int8> resource) async {
  return resource.value;
}

异步函数可能在await阻塞,以至于运行时系统可以检测到该await没有完成的可能性。在这种情况下,位于await之后的代码将永远不会执行,包括finally块,变量可能与其他一切一样被视为已死。

如果您自己不打算保持变量存活,请确保将可终结的对象传递给其他函数,而不仅仅是它的资源。

例如,当myFunction运行到其作用域的末尾时,不会通过finalizable保持存活,而someAsyncCall仍然可以继续执行。然而,finalizable本身是由someAsyncCall保持存活的。

void myFunction() {
  final finalizable = MyFinalizable();
  someAsyncCall(finalizable);
}

Future<void> someAsyncCall(MyFinalizable finalizable) async {
  // ..
}

class MyFinalizable implements Finalizable {
  // ..
}
注释
  • @Since('2.17')

属性

hashCode int
此对象的哈希码。
无设置器继承
runtimeType Type
对象运行时类型的表示。
无设置器继承

方法

noSuchMethod(Invocation invocation) → dynamic
当访问不存在的方法或属性时被调用。
继承
toString() String
此对象的字符串表示。
继承

运算符

operator ==(Object other) bool
相等运算符。
继承