我正在尝试创建一个快速,灵活和方便的API,接受可选的字符串参数.我希望用户能够通过:
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>>,
Run Code Online (Sandbox Code Playgroud)
foo(Some("aaa"));
Run Code Online (Sandbox Code Playgroud)
error[E0283]: type annotations required: cannot resolve `_: std::convert::Into<std::borrow::Cow<'_, str>>`
--> src/main.rs:12:5
|
12 | foo(Some("aaa"));
| ^^^
|
note: required by `foo`
--> src/main.rs:3:1
|
3 | / fn foo<'a, T, O>(_bar: O)
4 | | where
5 | | T: Into<Cow<'a, str>>,
6 | | O: Into<Option<T>>,
7 | | {}
| |__^
Run Code Online (Sandbox Code Playgroud)
它可以使它工作吗?
我很确定你不能创建这样的功能,但仍然符合人体工程学.问题是泛型类型中可能存在零个,一个或多个潜在路径:
+-----------+
| |
+---------> Option<B> +----------------------+
| | | |
+-+-+ +-----------+ +-----------v----------+
| | | |
| A | | Option<Cow<'a, str>> |
| | | |
+-+-+ +-----------+ +-----------^----------+
| | | |
+---------> Option<C> +----------------------+
| |
+-----------+
Run Code Online (Sandbox Code Playgroud)
这就是你得到错误的原因:不清楚具体类型T应该是什么,因此调用者必须将它提供给编译器.在这里我使用涡轮机:
foo::<&str, _>(Some("aaa"));
foo::<String, _>(Some("aaa".to_string()));
foo::<&str, Option<&str>>(None);
Run Code Online (Sandbox Code Playgroud)
我建议重新评估您的API设计.可能的方向包括:
创建一个自定义的结构和实施From针对特定的具体类型(例如&str,Option<String>等).传递None仍然会有问题,因为它不清楚None它是什么类型:一个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>);
}
Run Code Online (Sandbox Code Playgroud)切换到构建器模式 - 我的首选方向:
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();
}
Run Code Online (Sandbox Code Playgroud)
请注意,这样就不需要调用者完全指定Some; 使用该name功能意味着存在.如果需要,您可以创建一个without_name函数将其重新设置None.
也可以看看:
| 归档时间: |
|
| 查看次数: |
348 次 |
| 最近记录: |