Dan*_*Dan 6 d duck-typing metaprogramming
我是D的新手,我想知道是否可以方便地进行编译时检查的鸭子打字.
例如,我想定义一组方法,并要求为传递给函数的类型定义这些方法.它与interface
D 略有不同,因为我不必在任何地方声明"类型X实现接口Y" - 只能找到方法,否则编译将失败.此外,允许在任何类型上发生这种情况都是好的,而不仅仅是结构和类.我能找到的唯一资源是这个电子邮件线程,它表明以下方法是一种不错的方法:
void process(T)(T s)
if( __traits(hasMember, T, "shittyNameThatProbablyGetsRefactored"))
// and presumably something to check the signature of that method
{
writeln("normal processing");
}
Run Code Online (Sandbox Code Playgroud)
...并建议你可以将它变成一个库调用Implements,以便以下可能:
struct Interface {
bool foo(int, float);
static void boo(float);
...
}
static assert (Implements!(S, Interface));
struct S {
bool foo(int i, float f) { ... }
static void boo(float f) { ... }
...
}
void process(T)(T s) if (Implements!(T, Interface)) { ... }
Run Code Online (Sandbox Code Playgroud)
对于未在类或结构中定义的函数,是否可以执行此操作?还有其他/新方法吗?有类似的事吗?
显然,这组约束类似于Go的类型系统.我不是要开始任何火焰战争 - 我只是以一种Go也会很好用的方式使用D.
这实际上是D中常见的事情.这是范围如何工作.例如,最基本的范围类型 - 输入范围 - 必须具有3个功能:
bool empty(); //Whether the range is empty
T front(); // Get the first element in the range
void popFront(); //pop the first element off of the range
Run Code Online (Sandbox Code Playgroud)
然后使用模板化函数std.range.isInputRange
来检查类型是否是有效范围.例如,最基本的重载std.algorithm.find
看起来像
R find(alias pred = "a == b", R, E)(R haystack, E needle)
if (isInputRange!R &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{ ... }
Run Code Online (Sandbox Code Playgroud)
isInputRange!R
是true
如果R
是一个有效的输入范围内,并且is(typeof(binaryFun!pred(haystack.front, needle)) : bool)
是true
如果pred
接受haystack.front
和needle
并返回一个类型的隐式转换为bool
.所以,这个重载完全基于静态鸭子类型.
至于isInputRange
它本身,它看起来像
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = void; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
Run Code Online (Sandbox Code Playgroud)
它是一个同名模板,所以当它被使用时,它会被带有名称的符号替换,在这种情况下,它是一个类型的枚举bool
.这bool
就是true
表达式的类型是非void
.typeof(x)
导致void
表达式无效; 否则,它是表达式的类型x
.而is(y)
结果true
,如果y
是非void
.因此,如果表达式中的代码编译,isInputRange
将最终成为,否则.true
typeof
false
表达式isInputRange
验证您可以声明一个类型的变量R
,该变量R
具有一个empty
可以在条件中使用的成员(可以是函数,变量或其他),该R
函数名为popFront
不带参数的函数,并且R
具有front
返回值的成员.这是输入范围所期望的API,并且typeof
如果R
遵循该API,则内部表达式将编译,因此isInputRange
将true
用于该类型.否则,它会false
.
D的标准库有很多这样的同名模板(通常称为traits),并在模板约束中大量使用它们.std.traits
特别是有很多.所以,如果你想要更多关于如何编写这些特征的例子,你可以在那里查看(虽然其中一些相当复杂).这些特性的内部结构并不总是特别漂亮,但它们确实很好地封装了鸭子类型测试,因此模板约束更清晰,更易理解(如果将这些测试直接插入到它们中,它们会更加,更加丑陋).
所以,这是D中静态鸭子打字的常规方法.确实需要一些练习来弄清楚如何编写它们,但这是标准的方法,它可以工作.曾经有人建议尝试提出类似于你的Implements!(S, Interface)
建议的东西,但实际上还没有真正的东西,而这种方法实际上不那么灵活,使它不适合很多特征(虽然它当然可以与基本的一起工作).无论如何,我在这里描述的方法目前是标准的方法.
另外,如果您对范围了解不多,我建议您阅读此内容.
归档时间: |
|
查看次数: |
459 次 |
最近记录: |