You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中cart与cartCopy数组因对象引用同步变更问题求助

问题

我拥有cart和cartCopy两个数组,数组内存放着结构为{"product_name":"",variants:[],extras:[]}的CartData对象。数据已分别存入cart和cartCopy中。当我更新cart中的variant或extras时,会先创建独立的variantList和extrasList列表,但更新这两个列表时,cart和cartCopy中的对应值也会随之改变,即便我并未对它们进行更新操作。

相关代码

修改变体及设置待编辑商品的Provider类

class ProductDetailsProvider extends ChangeNotifier {
  List<VariantDetails>? variants = [];
  List<VariantDetails>? selectedVariants = [];
  List<AddOnDetails>? selectedExtras = [];

  addVariant(VariantDetails? item) {
      var exist =
          variants?.indexWhere((element) => element.typeID == item?.typeID);
      if (exist != -1) {
        variants?[exist!] = item!;
      } else {
        variants?.insert(0, item!);
      }
    }

  setProduct(CartData item) async {
    variants = item.variant;
    selectedExtras = item.extras;
    selectedVariants = item.variant;
    notifyListeners();
  }
}

加入购物车类

class CartProvider extends ChangeNotifier {
  List<CartData>? cart = [];
  List<CartData>? cartCopy = [];

  addToCart(context, CartData cartItem, isUpdate) async {
      cart?[exist!] = cartItem;
      cartCopy?[exist!] = cartItem;
  }
}

每当我更新variant时,cart和cartCopy中的variant也会同步变化。请问如何分离cart中的值,避免这种同步变更?

解决方法

这是因为Dart中引用类型(比如List、自定义对象)都是传递引用而非复制值。你直接将item.variant赋值给variants、selectedVariants,把item.extras赋值给selectedExtras,本质是让这些变量指向同一块内存地址的列表,所以修改其中一个,其他引用的地方也会跟着变化。要解决这个问题,需要对列表和对象进行深拷贝,切断引用关系。

1. 对商品变体和附加项列表做深拷贝

方案一:浅拷贝(适用于元素为不可变对象的场景)

如果VariantDetails和AddOnDetails是不可变类(属性都是final且不需要修改内部值),可以直接用List的toList()方法创建新列表副本:

setProduct(CartData item) async {
  variants = item.variant?.toList();
  selectedExtras = item.extras?.toList();
  selectedVariants = item.variant?.toList();
  notifyListeners();
}

方案二:深拷贝(推荐,适用于需要修改对象内部属性的场景)

给VariantDetails和AddOnDetails添加copyWith方法,用于创建对象的独立副本:

class VariantDetails {
  final String? typeID;
  // 其他属性...

  VariantDetails({this.typeID/*, 其他参数*/});

  // 实现copyWith方法,生成新对象
  VariantDetails copyWith({
    String? typeID,
    // 其他属性的可选参数
  }) {
    return VariantDetails(
      typeID: typeID ?? this.typeID,
      // 其他属性同理,用传入值或当前对象的值
    );
  }
}

class AddOnDetails {
  final String? id;
  // 其他属性...

  AddOnDetails({this.id/*, 其他参数*/});

  AddOnDetails copyWith({
    String? id,
    // 其他属性的可选参数
  }) {
    return AddOnDetails(
      id: id ?? this.id,
      // 其他属性同理
    );
  }
}

然后在setProduct方法中,通过map遍历原列表,用copyWith创建新对象并生成新列表:

setProduct(CartData item) async {
  variants = item.variant?.map((v) => v.copyWith()).toList();
  selectedExtras = item.extras?.map((e) => e.copyWith()).toList();
  selectedVariants = item.variant?.map((v) => v.copyWith()).toList();
  notifyListeners();
}

2. 对CartData对象做深拷贝

在CartProvider的addToCart方法中,直接赋值cartItem会让cart和cartCopy引用同一个对象,需要给CartData也添加copyWith方法实现深拷贝:

class CartData {
  final String? product_name;
  final List<VariantDetails>? variant;
  final List<AddOnDetails>? extras;

  CartData({this.product_name, this.variant, this.extras});

  CartData copyWith({
    String? product_name,
    List<VariantDetails>? variant,
    List<AddOnDetails>? extras,
  }) {
    return CartData(
      product_name: product_name ?? this.product_name,
      // 对变体列表做深拷贝
      variant: variant?.map((v) => v.copyWith()).toList() ?? this.variant?.map((v) => v.copyWith()).toList(),
      // 对附加项列表做深拷贝
      extras: extras?.map((e) => e.copyWith()).toList() ?? this.extras?.map((e) => e.copyWith()).toList(),
    );
  }
}

修改addToCart方法,使用拷贝后的对象:

addToCart(context, CartData cartItem, isUpdate) async {
  // 创建cartItem的深拷贝,避免cart和cartCopy共享同一对象
  final copiedItem = cartItem.copyWith();
  cart?[exist!] = copiedItem;
  cartCopy?[exist!] = copiedItem;
}

总结

核心思路就是通过深拷贝创建独立的列表和对象实例,让cart、cartCopy以及编辑用的variants、selectedExtras等变量指向不同的内存空间,从而避免修改一处导致多处同步变化的问题。

内容的提问来源于stack exchange,提问作者VDTe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 05:24:20