在公共函数中使用私有类型的最佳方式是啥? [复制]
Posted
技术标签:
【中文标题】在公共函数中使用私有类型的最佳方式是啥? [复制]【英文标题】:What's the best way to use a private type in a public function? [duplicate]在公共函数中使用私有类型的最佳方式是什么? [复制] 【发布时间】:2020-06-10 12:40:11 【问题描述】:我有以下代码:
use std::convert::From, Into;
#[derive(PartialEq, Debug)]
enum FindBy<'f>
U(&'f usize),
S(&'f str),
ST(&'f String),
impl<'f> From<&'f usize> for FindBy<'f>
fn from(v: &'f usize) -> Self
Self::U(v)
impl<'f> From<&'f str> for FindBy<'f>
fn from(v: &'f str) -> Self
Self::S(v)
impl TileSet
pub fn find<'r, 'ts: 'r, K: Into<FindBy<'r>>>(&'ts self, key: K) -> &'r Tile
match key.into()
FindBy::S(k) => &self.list.get(k).unwrap(),
FindBy::ST(k) => &self.list.get(k).unwrap(),
FindBy::U(k) => match &self.list.get_index(*k)
Some((_, v)) => &v,
_ => todo!(),
,
导致此警告:
warning: private type `prelude::sys::element::tile_set::FindBy<'r>` in public interface (error E0446)
--> src/sys/element/tile_set.rs:46:5
|
46 | / pub fn find<'r, 'ts: 'r, K: Into<FindBy<'r>>>(&'ts self, key: K) -> &'r Tile
47 | | match key.into()
48 | | FindBy::S(k) => &self.list.get(k).unwrap(),
49 | | FindBy::ST(k) => &self.list.get(k).unwrap(),
... |
54 | |
55 | |
| |_____^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
FindBy
从未公开——它的目的是提供一个白名单以允许一个参数采用多种类型,但该类型本身绝不打算在外部使用,仅供内部使用,但它抱怨私有类型在公共界面中。
请允许我澄清一下,FindBy
永远不会在它所在的模块/文件之外使用,但它是函数签名的一部分,函数是 public
。
我不想公开 FindBy
,但它从来没有公开,但因为它在公共函数中用于为参数提供类型白名单,所以 Rust 抱怨。
解决这个问题的最佳方法是什么?
【问题讨论】:
很难回答您的问题,因为它不包含minimal reproducible example。您提供的代码不会产生您所询问的错误。如果您尝试在Rust Playground 上重现您的错误,如果可能的话,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后在edit 您的问题中包含附加信息。您可以使用Rust-specific MRE tips 来减少您在此处发布的原始代码。谢谢! 您的问题似乎可以通过How to reference private types from public functions in private modules? 或Private inner module returning private item gives “private type in public interface” error 的答案得到解答。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。 这些问题似乎是关于返回私有类型,这不是我要问的,因为我没有返回私有类型;正如我所说的“但类型本身绝不打算在外部使用,仅供内部使用”。 "returning" vs "accepting" 在这里不相关,关键是类型在签名中。您是否尝试解决方案以查看它们是否有效? The code you have provided does not generate the error you are asking about. 【参考方案1】:将参数限制为几种可能类型之一的常用解决方案是使用Sealed traits。
因此,对于您的 find
函数,您可以拥有 FindBy
特征(如链接中所述已密封,因此没有其他人可以实现它),而不是拥有 enum FindBy
并在其变体上调度封装了每种类型的不同逻辑,大致是这样的(未测试):
impl TileSet
pub fn find<K: FindBy>(&self, key: K) -> &Tile
key.find_in(self)
pub trait FindBy: private::Sealed
fn find_in<'ts>(self, _: &'ts TileSet) -> &'ts Tile;
impl FindBy for &'_ usize
fn find_in(self, tileset: &'ts TileSet) -> &'ts Tile
match &tileset.list.get_index(*self)
Some((_, v)) => &v,
_ => todo!(),
// impl FindBy for &'_ str ...
// impl FindBy for &'_ String ...
mod private
pub trait Sealed
impl Sealed for &'_ usize
impl Sealed for &'_ str
impl Sealed for &'_ String
如果你希望它只能通过TileSet::find
使用,你也可以将方法(我称之为find_in
)移动到私有特征。此外,您可能需要考虑为usize
而不是&'_ usize
实现特征(但也许您有充分的理由将其作为参考)。
【讨论】:
那你同意这个问题是How to reference private types from public functions in private modules?的重复? 所以,公开类型并将impl TileSet
更改为impl TileSet: private::Sealed
?
Shepmaster:我认为这个问题足够不同,可以有自己的答案,因为 OP 中的私有枚举实际上只存在于允许 find
将多个不同的公共类型作为其参数。您对该问题的回答没有提到密封特征,因为它们很可能不适用于那里;恕我直言,他们在这里。
Thermatix:不,但我会添加到我的答案中以澄清。
@jplatte,感谢您是唯一一个有足够理性来实际阅读问题的人。以上是关于在公共函数中使用私有类型的最佳方式是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
C#:如果一个类有两个构造函数,这些构造函数共享一些代码的最佳方式是啥? [复制]