如何获得扩展方法来更改 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();
foo
和 sameFoo
还会指代同一个对象吗?如果他们现在指的是不同的对象,那将是令人惊讶的。但是,如果它们仍然引用同一个对象,那就意味着 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。
southwest
和 northeast
是 LatLngBounds
的 final
个字段。所以你不能用扩展来改变它们
https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.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();
foo
和 sameFoo
还会指代同一个对象吗?如果他们现在指的是不同的对象,那将是令人惊讶的。但是,如果它们仍然引用同一个对象,那就意味着 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。
southwest
和 northeast
是 LatLngBounds
的 final
个字段。所以你不能用扩展来改变它们
https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/location.dart