如何判断Dart中两个函数是否相等?实现唯一函数列表
Dart中检测函数实例唯一性的问题及解决方案
问题原因
你遇到的核心问题是:Dart里每次在循环内部定义函数时,都会生成一个全新的闭包实例。哪怕函数的代码逻辑完全一致,这些实例的引用地址也不相同。而List.contains()方法默认用==判断,函数的==是比较引用身份,所以每次检测都会返回false,导致重复添加。同理,每个闭包的hashCode都是唯一的,靠哈希值检测也没用。
而把函数定义移到循环外时,整个循环引用的是同一个函数实例,所以contains能正确识别,最终列表长度为1。
可行解决方案
因为循环内生成的闭包本质是不同实例,无法通过默认的身份判断来识别“逻辑相同”的函数,所以需要换一种思路去重:
1. 用包装类绑定唯一标识
创建一个包装类,把函数和一个业务层面的唯一标识绑定,存储包装类而非直接存函数。去重时比较标识而非函数实例:
import 'package:flutter/widgets.dart'; class ListenerWrapper { final String uniqueKey; final VoidCallback callback; ListenerWrapper(this.uniqueKey, this.callback); } // 使用示例 final listeners = <ListenerWrapper>[]; for (int i = 0; i < 5; i++) { void listener() => setState(() {}); // 根据业务逻辑生成唯一key,比如关联的组件ID、事件名称等 final wrapper = ListenerWrapper('refresh_state_listener', listener); if (!listeners.any((item) => item.uniqueKey == wrapper.uniqueKey)) { listeners.add(wrapper); } }
2. 让调用者提供唯一标识
作为库开发者,可以要求用户在注册监听器时传入一个唯一key,以此作为去重依据。这是很多第三方库的通用做法:
final listeners = <MapEntry<String, VoidCallback>>[]; void addListener(String key, VoidCallback callback) { if (!listeners.any((entry) => entry.key == key)) { listeners.add(MapEntry(key, callback)); } } // 调用示例 for (int i = 0; i < 5; i++) { addListener('refresh_state', () => setState(() {})); }
注意:不推荐的方式
不要尝试通过反射(dart:mirrors)获取函数源代码来比较,一来Flutter环境禁用了反射,二来逻辑相同但作用不同的函数可能源代码一致,容易误判。
内容的提问来源于stack exchange,提问作者buttonsrtoys
相关产品推荐
相关产品推荐

