简体   繁体   English

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

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

I have bounds .我有bounds bounds should be extended with new LatLng.应使用新的 LatLng 扩展边界。

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

I want to implement this extension:我想实现这个扩展:

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*/   );

  }
}

It would have been possible to change the original object if its properties were not final.如果原始 object 的属性不是最终的,则可以更改它。 This is not the case for LatLngBounds.southwest and LatLngBounds.northeast . LatLngBounds.southwestLatLngBounds.northeast并非如此

If I remember correctly, LatLngBounds is an immutable class representing a latitude/longitude aligned rectangle.如果我没记错的话, LatLngBounds是一个不可变的 class 代表一个纬度/经度对齐的矩形。

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

If this extend modifies this how would you access this?如果这个extend修改了this ,你将如何访问它?

I think this extend should rather be part of some kind of State Management.我认为这个extend应该是某种 State 管理的一部分。

See the following, using Riverpod Hooks package :请参阅以下内容,使用Riverpod Hooks package

Instead of changing the object (since it is immutable), you return a new one in your extension:不要更改 object(因为它是不可变的),而是在扩展中返回一个新的:

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),
    );
  }
}

Then, when you need to modify the object, you work on a State Object managed by Flutter or any other State Management System : Then, when you need to modify the object, you work on a State Object managed by Flutter or any other 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);
  }
}

Here is a Minimal Working Example:这是一个最小的工作示例:

在此处输入图像描述

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),
    );
  }
}

You can change the fields if they are not final.如果它们不是最终的,您可以更改这些字段。 But you cannot change object as this = new Class() .但是您不能将 object 更改为this = new Class()

PS. PS。 southwest and northeast are final fields of LatLngBounds . southwestnortheastLatLngBoundsfinal字段。 So you can't change them with an extension https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart所以你不能用扩展https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart来改变它们

Extension methods can mutate this , but they cannot reassign/rebind it.扩展方法可以改变this ,但不能重新分配/重新绑定它。 Note that that is true for normal methods too and isn't specific to extension methods.请注意,普通方法也是如此,并不特定于扩展方法。

Suppose that reassigning this were possible.假设重新分配this是可能的。 Consider the following code:考虑以下代码:

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

foo.reassignThis();

Would foo and sameFoo still refer to the same object? foosameFoo仍然指代相同的 object? It would be surprising if they now referred to different objects.如果他们现在提到不同的对象,那将是令人惊讶的。 However, if they do still refer to the same object, that would mean that the VM/runtime would need to be able to easily and quickly find all references to an object so that it can update them.但是,如果它们仍然引用相同的 object,则意味着 VM/运行时需要能够轻松快速地找到对 object 的所有引用,以便更新它们。

Even if the VM/runtime could do that, then consider:即使 VM/运行时可以做到这一点,也要考虑:

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);
}

After calling reassignThis() , what would derived be?调用reassignThis()后, derived的会是什么? Would it still be a Derived object?它仍然是Derived的 object 吗? Would it be just a Base object?它只是一个Base object 吗?

Reassigning this isn't possible, and it isn't something that could be improved;重新分配this是不可能的,也不是可以改进的; fundamentally it doesn't make much sense.基本上它没有多大意义。


Now, instead of reassigning this , you could implement something like:现在,您可以实现类似的东西,而不是重新分配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 */);
  }
}

and then try to use MyLatLngBounds everywhere instead of LatLngBounds .然后尝试在任何地方使用MyLatLngBounds而不是LatLngBounds

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM