Почему я получаю сообщение об ошибке «Этот универсальный параметр должен использоваться с параметром универсального типа» для следующего кода?

Я не могу понять, почему следующий код выдает ошибку this generic parameter must be used with a generic type parameter

use anyhow::Result;
use std::path::Path;

fn test_file(path: impl AsRef<Path>, filename: &str) -> Result<Option<impl AsRef<Path>>> {
    ...
    if path.join(filename).exist() {
        Ok(Some(path))
    } else if current_directory == path {
        Ok(None)
    } else {
        test_file(path.parent().context("{filename} not found")?, filename)
    }
}

Как вы можете видеть, это рекурсивная функция, и я получаю ошибку в условии else при передаче пути к родительскому каталогу, но, что удивительно, если я изменю тип возвращаемого значения на Result<bool> со следующим телом функции, тогда компилятор пройдет без каких-либо ошибок.

use anyhow::Result;
use std::path::Path;

fn test_file(path: impl AsRef<Path>, filename: &str) -> Result<bool> {
    ...
    if path.join(filename).exist() {
        Ok(true)
    } else if current_directory == path {
        Ok(false)
    } else {
        test_file(path.parent().context("{filename} not found")?, filename)
    }
}

Детская площадка

Я не могу понять, что я здесь делаю не так.

Почему ты возвращаешься impl AsRef<Path>? Просто вернитесь PathBuf.

Chayim Friedman 01.05.2024 22:16

Верно, но я не могу понять, почему компилятор жалуется на impl AsRef<Path>?

sudeeptarlekar 01.05.2024 22:27

Если честно, я тоже не могу этого понять. Если вы последуете предложению компилятора и выполните test_file<T: AsRef<Path>>(path: T,, он все равно будет жаловаться (с совершенно бессмысленной диагностикой, я мог бы добавить), но если вы это сделаете test_file(path: &Path,, то он будет работать. Кажется, это комбинация path общего и возвращаемого положения impl, но будь я проклят, если смогу понять, почему. Мне он чем-то напоминает запах жука, но я не могу сказать этого наверняка.

cdhowie 01.05.2024 22:32

@cdhowie, хотя ошибка кажется запутанной, она буквально описывает проблему, вы не можете использовать test_file с &Path, потому что это не гарантирует возврат того же типа, что и при вызове с T, вы должны использовать параметр типа T→ "этот общий параметр должен использоваться с параметром универсального типа» — это буквально то, что вам нужно сделать.

cafce25 01.05.2024 23:32

ссылка на репродукцию игровой площадки: play.rust-lang.org/…

user4815162342 01.05.2024 23:53

@cafce25 cafce25 Тогда формулировка сообщения об ошибке просто ужасна.

cdhowie 02.05.2024 00:53
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
6
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Простой ответ — всегда возвращаться PathBuf. Сообщить вызывающему объекту о том, что у него есть собственное значение, на самом деле полезно, поскольку это позволяет избежать ненужного клонирования, если ему понадобится превратить его в собственное значение.

fn test_file(path: impl AsRef<Path>, filename: &str) -> Result<Option<PathBuf>> {

(Детская площадка)

Ответ принят как подходящий

Проблема в том, что возвращаемый тип может зависеть от параметра типа1, поэтому единственный допустимый test_file для рекурсии должен иметь те же параметры типа, что и текущий, но &Path (результат path.parent().context("{filename} not found")?) не обязательно совпадает с тип передан.

Вот пример этого:

trait Foo {
    type A: AsRef<str>;
    fn foo(&self) -> Self::A;
}

impl Foo for () {
    type A = &'static str;
    fn foo(&self) -> &'static str {
        "unit"
    }
}

impl Foo for String {
    type A = String;
    fn foo(&self) -> String {
        String::from("string")
    }
}

fn test(x: impl Foo) -> impl AsRef<str> {
    x.foo()
}

fn main() {
    dbg!(test(String::new()).as_ref());
    dbg!(test(()).as_ref());
}

1) analyzing the body would show it's always a wrapped PathBuf but that's not something the compiler does factor in

Другие вопросы по теме