在我写的一个 crate 中,我有一堆内部的struct
对用户公开,并且共享一些代码。一些共享代码是公共(public)的,一些是内部实现的。为了有效地共享代码,我正在使用宏,但是现在该项目具有更多功能,这开始变得一团糟,对此的语义我不满意。
我想使用一个特质,但不公开其实现。例如:
pub trait MyTrait {
type Next;
// This function is for the user.
fn forward(&self) -> Self::Next {
self.do_the_job()
}
// This function is for the user.
fn stop(&self) {
self.do_the_job();
}
// This function is an implementation detail.
fn do_the_job(&self) -> Self::Next;
}
我希望用户看到并使用
forward
和stop
,而不是do_the_job
,而我的数据只能实现do_the_job
。是否可以将我的代码设计为执行类似的操作?我试图想像一些解决方案,但是什么都没想到。
Playground
在具有继承性的面向对象的语言中,我会做(伪代码):
public interface MyTrait {
type Next;
fn forward(&self) -> Self::Next;
fn stop(&self);
}
public abstract class MyCommonCode extends MyTrait {
fn forward(&self) -> Self::Next {
self.do_the_job()
}
fn stop(&self) {
self.do_the_job();
}
protected abstract fn do_the_job(&self) -> Self::Next;
}
public MyType extends MyCommonCode {
type Next = i32;
protected override fn do_the_job(&self) -> Self::Next {
// etc.
}
}
最佳答案
特性类似于interfaces:
接口(interface)旨在记录可用方法,而具有私有(private)方法的接口(interface)则毫无意义。相应地,在Rust中,您不能在一个特征中拥有不同级别的可见性。如果可以看到该特征,则始终可以看到所有特征。但是,Rust特征与接口(interface)有细微的不同:它们结合了声明和实现。我看到具有一些私有(private)功能的特征将是多么直观。
一段时间以来,可以将特征分为公共(public)部分和私有(private)部分。您将具有两个特征,一个特征包含您的公共(public)接口(interface),另一个特征具有您的私有(private)功能,但这是being removed in newer versions of Rust。
当前的解决方法仍然是分割特征,但是私有(private)部分现在必须由私有(private)模块中的公共(public)特征来表示。为了说明这一点,下面是一些示例代码:
// this module contains a public trait Inc, to increment a value
// and it implements it by using a private trait Add
mod my_math {
pub struct Val {
pub val: i32,
}
// this is necessary to encapsulate the private trait
// the module is private, so the trait is not exported
mod private_parts {
pub trait Add {
fn add(&mut self, i32);
}
}
// in the following code, we have to use adequate namespacing
impl private_parts::Add for Val {
fn add(&mut self, other: i32) {
self.val += other;
}
}
pub trait Inc: private_parts::Add {
fn inc(&mut self);
}
impl Inc for Val {
fn inc(&mut self) {
use my_math::private_parts::Add;
self.add(1)
}
}
}
fn main() {
use my_math::Inc;
let mut b = my_math::Val { val: 3 };
println!("value: {}", b.val);
b.inc();
println!("value: {}", b.val);
}