如何获得扩展方法来更改 Dart 中的原始对象?

How can I get an extension method to change the original object in Dart?

我有bounds。应使用新的 LatLng 扩展边界。

var bounds = LatLngBounds();
for (var latlng in _list) bounds.extend(latlng);

我想实现这个扩展:

extension LatLngBoundsExtend on LatLngBounds {
  extend(LatLng _latLng){
    //I want to change the object which this method is called from
    this = LatLngBounds(southwest: /* some magic code*/, northeast: /* some magic code*/   );

  }
}

如果原始对象的属性不是最终的,则可以更改它。 This is not the case for LatLngBounds.southwest and LatLngBounds.northeast.

如果我没记错的话,LatLngBounds 是一个不可变的 class,表示 latitude/longitude 对齐的矩形。

final myLatLngBounds = LatLngBounds(southwest, northeast);
myLatLngBounds.extend(latlng);

如果此 extend 修改 this 您将如何访问它?

我认为这 extend 应该是某种状态管理的一部分。

请参阅以下内容,使用 Riverpod Hooks package

无需更改对象(因为它是不可变的),您 return 在您的扩展中添加一个新对象:

extension RectX on Rect {
  Rect extend(Offset offset) {
    return Rect.fromLTRB(
      min(left, offset.dx),
      min(top, offset.dy),
      max(right, offset.dx),
      max(bottom, offset.dy),
    );
  }
}

然后,当您需要修改对象时,您可以在由 Flutter 或任何其他管理的状态对象上工作 State Management System:

final rectProvider =
    StateNotifierProvider<RectNotifier>((ref) => RectNotifier());

class RectNotifier extends StateNotifier<Rect> {
  RectNotifier([Rect state])
      : super(state ?? Rect.fromLTRB(100, 100, 200, 200));

  void extend(Offset offset) {
    state = state.extend(offset);
  }
}

这是一个最小的工作示例:

import 'dart:math' show min, max;

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() {
  runApp(
    ProviderScope(
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        home: HomePage(),
      ),
    ),
  );
}

class HomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final rect = useProvider(rectProvider.state);
    return Scaffold(
      body: GestureDetector(
        onTapDown: (details) =>
            context.read(rectProvider).extend(details.localPosition),
        child: Container(
          color: Colors.black12,
          padding: EdgeInsets.all(16.0),
          child: Stack(
            children: [
              Positioned(
                top: rect.top,
                left: rect.left,
                child: Container(
                    width: rect.width,
                    height: rect.height,
                    color: Colors.amber.shade400),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

final rectProvider =
    StateNotifierProvider<RectNotifier>((ref) => RectNotifier());

class RectNotifier extends StateNotifier<Rect> {
  RectNotifier([Rect state])
      : super(state ?? Rect.fromLTRB(100, 100, 200, 200));

  void extend(Offset offset) {
    state = state.extend(offset);
  }
}

extension RectX on Rect {
  Rect extend(Offset offset) {
    return Rect.fromLTRB(
      min(left, offset.dx),
      min(top, offset.dy),
      max(right, offset.dx),
      max(bottom, offset.dy),
    );
  }
}

扩展方法可以变异 this,但不能reassign/rebind。请注意,这对于普通方法也是如此,并不特定于扩展方法。

假设重新分配 this 是可能的。考虑以下代码:

var foo = Foo();
var sameFoo = foo;

foo.reassignThis();

foosameFoo 还会指代同一个对象吗?如果他们现在指的是不同的对象,那将是令人惊讶的。但是,如果它们仍然引用同一个对象,那就意味着 VM/runtime 需要能够轻松快速地找到对一个对象的所有 所有 引用,以便它可以更新它们。

即使VM/runtime可以做到,那么考虑一下:

class Base {
  Base(this.x);

  int x;

  void reassignThis() {
    this = Base(x + 1); // Not legal!
  }
}

class Derived extends Base {
  Derived(int x) : super(x);

  int y;
}

void main() {
  var derived = Derived(0);
  derived.reassignThis();
  print(derived.y);
}

调用 reassignThis() 后,derived 会是什么?它仍然是一个 Derived 对象吗?它只是一个 Base 对象吗?

重新分配 this 是不可能的,也不是可以改进的地方;从根本上说,它没有多大意义。


现在,您可以实现如下内容,而不是重新分配 this

class MyLatLngBounds implements LatLngBounds {
  MyLatLngBounds(this._actual);

  LatLngBounds _actual;

  LatLng get northeast => _actual.northeast;
  LatLng get southwest => _actual.southwest;
  // ... other methods that forward to [_actual] ...

  void extend(LatLng _latLng) {
    _actual = LatLngBounds(/* some magic code */);
  }
}

然后尝试在所有地方使用 MyLatLngBounds 而不是 LatLngBounds

如果字段不是最终的,您可以更改它们。但是您不能将对象更改为 this = new Class().

PS。 southwestnortheastLatLngBoundsfinal 个字段。所以你不能用扩展来改变它们 https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart