如何拥有特质的私有部分?
How to have a private part of a trait?
在我写的 crate 中,我有一堆内部 struct
s public 给用户,它们共享一些代码。一些共享代码是 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
.
是否可以设计我的代码来做类似的事情?我试着想象一些解决方案,但我什么都没有想到。
在具有继承性的面向对象语言中,我会这样做(伪代码):
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:
Traits are Rust’s sole notion of interface.
接口是用来记录可用方法的,拥有私有方法的接口是没有意义的。相应地,在 Rust 中,你不能在一个特征中有不同级别的可见性。如果你能看到特质,你总能看到它的全部。然而,Rust traits 与接口有微妙的不同:它们结合了声明和实现。我看到了具有一些私有函数的特征是多么直观。
有一段时间可以将特征拆分为 public 和私有部分。您将有两个特征,一个包含您的 public 接口,另一个包含您的私有功能,但这是 being removed in newer versions of Rust.
当前的解决方法仍然是拆分特征,但私有部分现在必须由私有模块中的 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);
}
在我写的 crate 中,我有一堆内部 struct
s public 给用户,它们共享一些代码。一些共享代码是 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
.
是否可以设计我的代码来做类似的事情?我试着想象一些解决方案,但我什么都没有想到。
在具有继承性的面向对象语言中,我会这样做(伪代码):
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:
Traits are Rust’s sole notion of interface.
接口是用来记录可用方法的,拥有私有方法的接口是没有意义的。相应地,在 Rust 中,你不能在一个特征中有不同级别的可见性。如果你能看到特质,你总能看到它的全部。然而,Rust traits 与接口有微妙的不同:它们结合了声明和实现。我看到了具有一些私有函数的特征是多么直观。
有一段时间可以将特征拆分为 public 和私有部分。您将有两个特征,一个包含您的 public 接口,另一个包含您的私有功能,但这是 being removed in newer versions of Rust.
当前的解决方法仍然是拆分特征,但私有部分现在必须由私有模块中的 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);
}