我尝试创建一个快速,灵活且方便的API,接受可选的字符串参数。我希望用户能够通过:
finally
None
"foo"
"foo".to_string()
(相当于Some("foo")
)"foo"
(相当于Some("foo".to_string())
)据我所知,处理"foo".to_string()
或"foo"
的最佳解决方案是"foo".to_string()
。另一方面,处理Into<Cow<'a, str>>
或"foo"
的最佳解决方案是Some("foo")
。
因此我尝试了这个,但它没有编译:
Into<Option<&'a str>>
fn foo<'a, T, O>(_bar: O)
where
T: Into<Cow<'a, str>>,
O: Into<Option<T>>,
foo(Some("aaa"));
是否可以使其有效?
答案 0 :(得分:5)
我很确定你不能创建这样的功能,但仍然符合人体工程学。问题是泛型类型中可能存在零个,一个或多个潜在路径:
+-----------+
| |
+---------> Option<B> +----------------------+
| | | |
+-+-+ +-----------+ +-----------v----------+
| | | |
| A | | Option<Cow<'a, str>> |
| | | |
+-+-+ +-----------+ +-----------^----------+
| | | |
+---------> Option<C> +----------------------+
| |
+-----------+
这就是你得到错误的原因:不清楚T
的具体类型应该是什么,因此调用者必须将它提供给编译器。在这里,我使用 turbofish :
foo::<&str, _>(Some("aaa"));
foo::<String, _>(Some("aaa".to_string()));
foo::<&str, Option<&str>>(None);
我建议您重新评估您的API设计。可能的方向包括:
为特定的具体类型(例如From
,&str
等)创建自定义结构并实施Option<String>
。传递None
仍然会有问题,因为不清楚None
的{{1}}是什么类型:Option<&str>
或Option<String>
?
use std::borrow::Cow;
fn foo<'a, C>(_bar: C)
where
C: Into<Config<'a>>,
{
}
struct Config<'a>(Option<Cow<'a, str>>);
impl<'a> From<&'a str> for Config<'a> {
fn from(other: &'a str) -> Config<'a> {
Config(Some(other.into()))
}
}
impl From<String> for Config<'static> {
fn from(other: String) -> Config<'static> {
Config(Some(other.into()))
}
}
impl<'a> From<Option<&'a str>> for Config<'a> {
fn from(other: Option<&'a str>) -> Config<'a> {
Config(other.map(Into::into))
}
}
impl From<Option<String>> for Config<'static> {
fn from(other: Option<String>) -> Config<'static> {
Config(other.map(Into::into))
}
}
fn main() {
foo("aaa");
foo("aaa".to_string());
foo(Some("aaa"));
foo(Some("aaa".to_string()));
foo(None::<&str>);
}
切换到构建器模式 - 我的首选方向:
use std::borrow::Cow;
#[derive(Debug, Clone, Default)]
struct Foo<'a> {
name: Option<Cow<'a, str>>,
}
impl<'a> Foo<'a> {
fn new() -> Self {
Self::default()
}
fn name<S>(mut self, name: S) -> Self
where
S: Into<Cow<'a, str>>,
{
self.name = Some(name.into());
self
}
fn go(self) {
println!("The name is {:?}", self.name)
}
}
fn main() {
Foo::new().go();
Foo::new().name("aaa").go();
Foo::new().name("aaa".to_string()).go();
}
请注意,这样就不需要调用者完全指定Some
;使用name
函数意味着存在。如果需要,您可以设置without_name
功能将其设置回None
。
另见: