Jump to Navigation

用rust语言实现C++的方法重载,overload

用rust语言实现C++的方法重载,overload

C++的重载方法,指的是方法名字相同,参数不同的一功能相似的方法。

一种重载是参数类型或者个数不同,但是返回值类型相同。 一种重载是参数类型或者个数不同,而且返回值类型也不同。

由于在rust语言中表达这两种方式有差别,所以区分开描述。

第一种情况,

假设C++类有如下方法,

class QString;

QString & QString::append(const QString & str); QString & QString::append(QChar ch);

这种代码在C++毫无违和感,语言级就支持,还比较好。

那么在rust实现同名的方法,显然不行的。

struct QString{};

// 错误的方式 impl QString { fn append(&mut self, s: &QString) -> QString { } fn append(&mut self, ch: &QChar) -> QString { } }

编译会报名字冲突。

要解决这个问题,需要使用rust的trait概念了,还有ducking type特性。

struct QString{};

trait QString_append { fn append(self) -> QString; }

impl QString { fn append(&mut self, args: T) -> QString { args.append(); } }

impl QString_append for (&QString) { fn append(self) -> QString { return QString{}; } }

impl QString_append for (&QChar) { fn append(self)->QString { return QString{}; } }

有点罗嗦吧,不过它能正常工作,分别实现了参数为&QString和&QChar类型的append方法。

不过,有一点需要解析一下,

在impl /struct/ QString{} 中,self指的是QString实例对象。

在impl /trait/ QString_append for xxx{}中,self指的是xxx部分,其实就是参数表。

参数表self的类型为tuple,可以使用tuple.0,tuple.1来取值,但是,如果只有一个元素,则要直接使用self。

这里的trait函数,还可以传递其他的参数,比如QString的实例可以传递过去,就变成了这样:

struct QString{};

trait QString_append { fn append(self, o: &mut QString ) -> QString; }

impl QString { fn append(&mut self, args: T) -> QString { args.append(); } }

impl QString_append for (&QString) { fn append(self, o: &mut QString) -> QString { return QString{}; } }

impl QString_append for (&QChar) { fn append(self, o: &mut QString)->QString { return QString{}; } }

当然也还可以继续添加参数,只要在声明trait与实现trait时做到参数匹配即可。

第二种情况

假设C++类有如下方法,

class QIODevice;

qint64 read(char *data, qint64 maxlen); QByteArray read(qint64 maxlen);

现在问题来了,如果直接按照原来的方式实现,根本无法声明一个合适的trait,是用QByteArray返回值呢,还是qint64返回值呢,这是个问题?

好在rust提供了generic功能,把返回值定义为一个generic模板类型好:

struct QIODevice{};

triat QIODevice_read { fn read(self, o: &mut QIODevice) -> RetType; }

impl QIODevice { fn read<RetType, T: QIODevice_read>(&mut self, args: T) -> RetType { let res = args.read(self); return res; } }

impl QIODevice_read for (i64) { fn read(self, o: &mut QIODevice) -> i64 { return 0; } }

impl QIODevice_read for (i64) { fn read(self, o: &mut QIODevice) -> QByteArray { return QByteArray{}; } }

这样就成了,有没有发现一个问题,参数列表完全相同。rust虽然啰嗦点,

好像重载功能比C++还强了,上面的情况相当于返回值的重载了,这是C++不支持的。

还需要注意的是在impl /struct/ QIODevice时,内部的read方法额外带了个RetType模板参数。

重载静态方法与非静态方法

方法名相同,但是一个是静态方法,另一个不是静态方法。

现在的情况是,rust支持非静态方法重载,也支持静态方法重载,但如果混合式的重载呢?

直接写的话,会报error: duplicate method [E0201]

rust是否有统一调用语法呢,这样行不行?好像1.5还是不支持哇。

只好采用改名大法了,把静态方法加个后缀,_s,然后静态方法与非静态方法都算重载了。

注,rust中 impl trait for (fn())的一个坑

impl traitfoo for (fn()->i32) {
    fn bar(&self);
}

fn foo() -> i32{
}

在调用的时候,直接使用bar(foo)是不行的,需要使用bar(foo as fn()->i32)。这算不算坑。

这样在使用起来得有多麻烦呢。

此坑一样的问题,http://stackoverflow.com/questions/33231806/implementing-traits-for-fn-type

好在有一种比较变态的解决方式。然而问题是这样不能重载其他的类型了???

这里还有个官方的issue: https://github.com/rust-lang/rust/issues/21086

添加新评论

Plain text

  • 不允许HTML标记。
  • 自动将网址与电子邮件地址转变为链接。
  • 自动断行和分段。
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.


Main menu 2

Story | by Dr. Radut