如何为D语言SumType实现opCmp并保留原有match等功能?
能否让D语言的SumType在兼容opCmp的同时保留原有功能?
答案是肯定的,以下是几种优雅的解决方案,既实现opCmp以支持max等排序操作,又完全保留SumType原有的match等功能:
方案一:用UFCS为SumType全局扩展opCmp
这是最简洁的方案,无需包裹结构体,直接为所有SumType添加比较能力,同时保留原生用法:
import std.sumtype; import std.algorithm.comparison : max; import std.stdio : writeln; import std.exception : assertThrown; import core.exception : AssertError; // 为所有SumType实现opCmp的UFCS函数 int opCmp(SumType)(SumType lhs, SumType rhs) if (isSumType!SumType) { return match!( (a, b) => a < b ? -1 : a == b ? 0 : 1, (_1, _2) => assert(0, "无法比较SumType中不同类型的值") )(lhs, rhs); } // 定义你的SumType别名 alias Foo = SumType!(int, string); void main() { Foo x = 3; Foo y = 5; Foo z = "hello"; writeln(max(x, y)); // 输出5,max函数正常工作 assert(x < y); assertThrown!AssertError(x < z); // 不同类型比较触发断言 // 完全保留原生match用法 x.match!( (int i) => writeln("整数: ", i), (string s) => writeln("字符串: ", s) ); // 输出"整数: 3" }
方案二:结构体包裹+手动转发match方法
如果需要对SumType做更多定制(比如添加额外属性/方法),可以用结构体包裹,并手动实现match转发,避免写.value:
import std.stdio : writeln; import std.exception : assertThrown; import std.algorithm.comparison : max; import core.exception : AssertError; import std.sumtype; struct Foo { SumType!(int, string) value; this(T)(T v) { value = v; } ref Foo opAssign(T)(T rhs) { value = rhs; return this; } int opCmp(Foo other) { return match!( (a, b) => a < b ? -1 : a == b ? 0 : 1, (_1, _2) => assert(0, "无法比较不同类型的值") )(value, other.value); } // 转发match调用到内部SumType auto match(Handlers...)(Handlers handlers) { return value.match!(handlers); } // 支持多SumType参数的match(可选) auto match(Handlers...)(auto ref Foo other, Handlers handlers) { return match!(handlers)(value, other.value); } } void main() { Foo x = 3; Foo y = 7; Foo z = "asdf"; assert(x < y); assertThrown!AssertError(x < z); assert(max(x, y) == y); // 直接调用match,无需.value x.match!( (int intValue) => writeln("收到整数"), (string strValue) => writeln("收到字符串") ); // 输出"收到整数" }
为什么原opDispatch方案失败?
match不是SumType的成员方法,而是std.sumtype模块中的全局模板函数。opDispatch只能转发结构体自身的成员函数,无法捕获全局模板函数的调用,因此无法通过opDispatch实现match的转发。
方案对比
| 方案 | 优点 | 适用场景 |
|---|---|---|
| UFCS扩展opCmp | 代码最简洁,无需修改原有SumType用法,全局生效 | 大多数通用场景,只需为SumType添加比较能力 |
| 结构体包裹+手动转发 | 可定制性强,能添加额外功能 | 需要对SumType做更多扩展(如添加属性、自定义方法)的场景 |
内容的提问来源于stack exchange,提问作者Conor O'Brien
相关产品推荐
相关产品推荐

