如何实现深度嵌套函数调用多态,新增类型无需修改isEqual主逻辑
方案1:注册式类型分发(优先推荐,纯函数+无方法结构体,对齐Haskell Eq类型类思路)
Haskell中通过Eq类型类为不同类型独立定义相等性实现,新增类型只需新增实例不需要修改原有逻辑,我们可以用全局注册表模拟这个模式,完全不侵入结构体定义:
// 相等实现注册表,key为类型标识,value为对应类型的相等判断函数 const eqImplRegistry = new Map() // 新增类型时仅需调用该方法注册相等实现,不需要修改isEqual主逻辑 function registerEqImpl(typeTag, eqFn) { eqImplRegistry.set(typeTag, eqFn) } // 主isEqual逻辑,永久不需要修改 function isEqual(a, b) { const typeA = getTypeTag(a) const typeB = getTypeTag(b) // 类型不同直接返回不等 if (typeA !== typeB) return false const eqImpl = eqImplRegistry.get(typeA) if (!eqImpl) throw new Error(`未实现${typeA}类型的自定义相等判断`) // 传入isEqual本身用于嵌套类型的递归判断 return eqImpl(a, b, isEqual) } // 自定义结构体仅需加类型标识字段,无任何方法 const Set = (items) => ({ _type: 'Set', items: items }) // 独立注册Set类型的相等实现 registerEqImpl('Set', (setA, setB, recursiveEq) => { if (setA.items.length !== setB.items.length) return false for (let i = 0; i < setA.items.length; i++) { if (!recursiveEq(setA.items[i], setB.items[i])) return false } return true }) // getTypeTag可根据你的语言类型系统实现,比如优先取结构体的_type字段,基础类型返回对应标识 function getTypeTag(val) { if (val && typeof val === 'object' && '_type' in val) return val._type // 基础类型自定义标签,不需要依赖原生==判断 if (typeof val === 'number') return 'Number' if (typeof val === 'string') return 'String' return typeof val } // 基础类型的相等逻辑也可以自定义注册,比如实现浮点数精度判断 registerEqImpl('Number', (a, b) => Math.abs(a - b) < 1e-9)
该方案完全满足纯函数+无方法结构体的要求,新增类型只需要单独写对应相等实现并注册即可,不需要改动任何现有逻辑。
方案2:显式传递相等函数(无全局状态,纯函数式)
如果不想引入全局注册表,可以将相等函数作为参数透传,适合多场景下需要不同相等语义的情况:
// 工具函数新增eq参数 function isIntersection(setTest, setA, setB, eq) { let i = 0 while (i < setTest.length) { const t = setTest[i] if (includes(setA, t, eq) || includes(setB, t, eq)) { i++ } else { return false } } return true } function includes(set, element, eq) { for (const x of set) { if (eq(element, x)) return true } return false } // 使用时传入组装好的相等函数即可 const customEq = combineEqImpls([setEq, numberEq, stringEq]) isIntersection(testSet, a, b, customEq)
方案3:必须使用类的实现方案
如果必须用类,可以采用静态方法分发的方式,不需要在实例上挂载方法:
class Set { constructor(items) { this.items = items } // 静态相等实现,不是实例方法 static isEqual(a, b, recursiveEq) { if (a.items.length !== b.items.length) return false for (let i = 0; i < a.items.length; i++) { if (!recursiveEq(a.items[i], b.items[i])) return false } return true } } // 主isEqual逻辑不需要修改 function isEqual(a, b) { if (a.constructor !== b.constructor) return false if (typeof a.constructor.isEqual === 'function') { return a.constructor.isEqual(a, b, isEqual) } // 基础类型自定义判断逻辑 return customPrimitiveEq(a, b) }
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

