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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:09:25