我一直很喜欢编写使用
AsRef<Path>
作为参数类型的 API,从那时起,调用函数就不必担心它是否有 str、String、PathBuf、Path 或其他什么,但在我运行的一些新代码中遇到一个问题,我编写的新函数采用两条路径,并且似乎我无法使用相同的灵活性,这是意想不到的。
我创建了一个孤立的(人为的)示例(请参阅playground):
use anyhow;
use std::path::Path;
fn do_some_file_stuff<P: AsRef<Path>>(path: P, path2: P) -> anyhow::Result<()> {
println!("some file stuff, with path: {} and path2: {}", path.as_ref().display(), path2.as_ref().display());
Ok(())
}
fn do_something<P: AsRef<Path>>(path: P, path2: P) -> anyhow::Result<()> {
do_some_file_stuff(path, path2)
}
fn do_another_thing<P: AsRef<Path>>(path: P) -> anyhow::Result<()> {
let outdir = path.as_ref().parent().unwrap_or(Path::new("."));
do_some_file_stuff(path, outdir)
}
fn main() -> anyhow::Result<()> {
let path_str = "data/myfile.txt";
do_something(path_str, "data/another.txt")?;
do_another_thing(path_str)?;
println!("success");
Ok(())
}
完整的错误输出是:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:16:29
|
13 | fn do_another_thing<P: AsRef<Path>>(path: P) -> anyhow::Result<()> {
| - expected this type parameter
...
16 | do_some_file_stuff(path, outdir)
| ------------------ ---- ^^^^^^ expected type parameter `P`, found `&Path`
| | |
| | expected all arguments to be this type parameter `P` type because they need to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected type parameter `P`
found reference `&Path`
note: function defined here
--> src/main.rs:4:4
|
4 | fn do_some_file_stuff<P: AsRef<Path>>(path: P, path2: P) -> anyhow::Result<()> {
| ^^^^^^^^^^^^^^^^^^ - ------- -------- this parameter needs to match the type parameter `P` type of `path`
| | |
| | `path2` needs to match the type parameter `P` type of this parameter
| `path` and `path2` all reference this parameter P
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to 1 previous error
我很困惑,因为我明白
&Path
符合 P
(AsRef<Path>
),但在这种情况下我看到了一个错误。 该错误似乎是说两个函数参数需要是相同的类型,但我通过阅读大量不同的文档和文章了解到,这种语法应该意味着它们可以是不同的类型,每个类型都实现相同的特征。
有人可以解释错误消息的含义以及如何编写代码以便编译吗?
更新(感谢@kmdreko 的评论): 我可以通过指定两个不同的类型标识符来更改函数签名以按我的预期工作:
fn do_some_file_stuff<P1: AsRef<Path>, P2: AsRef<Path>>(path: P1, path2: P2) -> anyhow::Result<()> {
println!("some file stuff, with path: {} and path2: {}", path.as_ref().display(), path2.as_ref().display());
Ok(())
}
考虑到我对这种语法的心理模型,这是没有意义的。 我通过阅读别人的代码了解了它,并且已经使用它一段时间了,但找不到确切的解释位置。 很高兴看到带有文档参考的答案,该文档参考解释了此语法+/或使用 Rust 更惯用的内容的替代示例代码。
使用
impl <trait>
创建“匿名通用参数”(参见RFC详细设计)
这是使用
impl
的替代语法(请参阅 playground):
fn do_some_file_stuff(path: impl AsRef<Path>, path2: impl AsRef<Path>) -> anyhow::Result<()> {
println!("some file stuff, with path: {} and path2: {}", path.as_ref().display(), path2.as_ref().display());
Ok(())
}