这是一篇简单介绍julia里面的holy trait的文章,大部分参考了这篇文章,节选了一部分将英文翻译成中文,毕竟元编程还不是很熟高级的实现还没太弄明白。
原因
由于julia采用的是多重派发和单继承,所以在对某些功能进行拓展时就很不现实,比如有一个已经实现了的功能,需要对新的类进行适配,就需要修改源函数。给一个例子:
1 | aslist_direct(x) = [x] |
这是把一个输入变量变成列表的函数,已经实现的是对于AbstractArray, Tuple
不进行变换,但是还有很多不是标量,不需要进行操作的类型,此时用这个类型进行输入就会产生错误的结果。常规的解决办法就是复制上面的代码对新类型创建一个新的函数,但是重复代码是糟糕的。
我们能否对一些类型就行标注,是否为标量。一个解决的办法是通过抽象类型,使标量类型称为它的子类,我们就能写出下面的代码:
1 | aslist(x::AbstracScalar) = [x] |
但是很多类都已经有了父类,而且在julia中只能有一个父类,所以这个办法不太行。
Trait
另一个解决办法就是采用trait
,trait
在julia中的实现是采用一个对类型返回用来进行多重派发的类型值的函数。这被广泛应用在index,broadcast,iterator
之中。
trait
非常实用,因为你只需要写一写声明语句,而不需要像上面一样重复代码。而且这还狠快,因为它们是类型的pure function
,julia编译器能够在编译时对它们进行优化,对它们采用静态分配到目标函数,所以在运行时不会被计算。
实现
我们首先需要创建trait函数将要返回的值的类型,它们应该是具体的类型,并且不需要任何数据。尽管它们不需要超类,实际中还是给它们一个超类,来管理trait。下面是实现
trait function
1 | # 返回值的类型 |
dispatch traits
1 | aslist(x::T) where T = aslist(scalarness(T), x) |
这就是基本的trait的实现了,还有更高级的基于类型方法的,和采用元编程来使得类型稳定加速基于类型方法的trait,这些看随着学习的深入什么时候再抄过来吧。