能否从trait中访问struct字段?

45

特质(Traits)用于将一些函数从结构体中分组实现,但是否可以从特质中访问结构体字段?

我可以想象在特质中声明字段,以便将字段也抽象化。我没有找到这样的语法;是否有其他解决方案?否则,无法使用特质具有非静态方法,对吗?

我熟悉C#的面向对象编程,并正在尝试适应Rust中我已经熟悉的C# OOP功能。

3个回答

49

这听起来好像您误解了traits的工作原理。traits不能有字段。如果您想从trait中提供对字段的访问权限,则需要在该trait中定义一个方法(比如说,get_blah)。

如果您正在询问是否可以从该结构体的trait实现中访问该结构体的字段,则是的。该结构体知道它自己的类型,因此没有问题。

trait Pet {
    fn is_smelly(&self) -> bool;
}

struct Dog {
    washed_recently: bool,
}

impl Pet for Dog {
    fn is_smelly(&self) -> bool {
        !self.washed_recently
    }
}

如果你正在编写一个特质的默认实现(即,在特质内部定义方法体),那么不,你不能访问字段。默认实现只能使用在特质中定义或在父特质中定义的方法。


14
编写结构体成员的访问方法可能很繁琐,但需要注意的是,优化器很可能会删除函数调用,使其同样有效率。 - Shepmaster
3
您的编辑基本上就是我所说的。但是当我不能在默认实现中使用字段时,Rust 真的不允许使用经典的继承模式,对吗?比如,C# 有一个从 Stream 继承而来的 FileStream 类。如果您无法访问结构体的字段,您将如何在 Rust 中实现类似的功能呢? - Reignbeaux
2
没错 - Rust没有经典继承。它有非常出色的组合能力,因为结构体可以嵌套在其他结构体中而不会增加额外的开销。 - Shepmaster
1
那会是什么样子呢?只是拥有另一个结构的字段,还是有类似于Go中(虚拟字段)直接访问字段成员的语法糖? - Reignbeaux
@Reignbeaux,遗憾的是,没有一种很好的方法可以直接访问嵌套结构体中的字段,假装嵌套不存在。你必须说foo.nested.field - Shepmaster

28

定义trait的默认实现中的字段是很有用的,这样实现trait的结构体就总是具有相同的字段。

显然,Rust团队也认为如此,但根据这个RFC,它仍在不断改进中。这是一项重大改变,已被推迟,因此我的看法是:目前还不能做到,但将来可能可以做到。

目前,您必须使用功能较弱的traits。


13
2022年4月底!仍然没有任何消息。 - garma

8

你可以在默认 trait 实现中使用访问器函数,使其在子实现中返回字段的值/引用并返回默认值。在默认实现的其他 fn 中使用它,并在子实现中重新定义访问器。默认实现的 fn 将使用重新定义的访问器作为其虚拟 fn。


1
这似乎是一个不错的解决方法。Trait 的默认实现不能直接访问结构体字段(因为 Trait 不能像 Java 和许多其他 OOP 语言一样拥有成员变量),但如果您将其声明放在 Trait 中,它们可以访问 getter/setter,并且在我看来提供了与访问结构体字段相同的功能。 - Meet Sinojia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接