D语言(LDC2)模板函数调用时delegate推导为void及自定义Option问题
搞定D语言LDC2下基于Algebraic实现Option类型的模板函数问题
我来帮你梳理并解决你遇到的这两个问题:模板函数调用时delegate被推导为void,还有getValue、isDefined便利函数的实现问题。
首先先把你的Option类型定义补全并优化下,确保基础结构没问题:
import std.variant; struct None{}; struct Some(T){ T t; alias t this; T get(){ return t; } }; alias Option(T) = Algebraic!(Some!(T), None); Option!T some(T)(T t){ return Option!T(Some!T(t)); } Option!T none(T)(){ return Option!T(None()); }
接下来逐个解决问题:
1. 实现正确的getValue和isDefined函数
你之前写的函数里VariantN!(size, Some!T, None)其实没必要这么写,因为Option!T本身就是Algebraic的别名,而Algebraic已经封装了VariantN的细节,直接用Option!T当参数就行。
getValue函数
这个函数要从Some类型里安全取值,最好先做类型检查,避免运行时崩溃:
T getValue(T)(Option!T opt){ // 用peek方法安全检查是否是Some类型 if (auto someVal = opt.peek!(Some!T)){ return someVal.t; } // 这里可以根据需求抛异常或者返回T的默认值 throw new Exception("当前Option是None,无法获取值"); }
isDefined函数
判断Option是不是Some类型,直接用Algebraic自带的has方法最方便:
bool isDefined(T)(Option!T opt){ return opt.has!(Some!T); }
2. 解决delegate被推导为void的问题
这种情况一般是编译器没法正确推断delegate的类型,大概率是模板函数的签名不够明确,或者传递的delegate参数有歧义。
举个例子,如果你的模板函数是这样的:
void processOption(T)(Option!T opt, delegate(T) handler){ if (opt.isDefined!T){ handler(opt.getValue!T); } }
调用时如果编译器推导出错,你可以显式指定模板参数帮它一把:
auto myOpt = some(42); processOption!int(myOpt, (int val) => writeln(val));
或者调整函数签名,把delegate的类型和Option的T绑定死,让编译器更容易推断:
void processOption(T)(Option!T opt, void delegate(T) handler){ if (opt.isDefined!T){ handler(opt.getValue!T); } }
这样调用的时候,编译器能通过Option!T的T自动推断delegate的参数类型,就不会乱推导成void了。
另外用lambda的时候,尽量让参数类型明确,或者利用D的自动推断,比如:
myOpt.processOption((val) => writeln(val)); // 只要processOption的签名正确,编译器会自动知道val是int类型
测试一下效果
把这些代码拼起来跑个测试:
import std.stdio; void main(){ Option!int opt1 = some(100); Option!int opt2 = none!int(); writeln(opt1.isDefined!int); // 输出true writeln(opt2.isDefined!int); // 输出false writeln(opt1.getValue!int); // 输出100 // opt2.getValue!int; // 取消注释会抛出异常 opt1.processOption!int((int val) => writeln("处理值:", val)); // 输出"处理值:100" }
内容的提问来源于stack exchange,提问作者Russoul
相关产品推荐
相关产品推荐

