0
use std::path::Path;
use std::path::PathBuf;

struct Deploy(PathBuf);

impl Deploy {
    fn values_yaml(self) -> Path {
        let values_yaml = self.0.join("helm").join("chart").join("values.yaml");
        values_yaml
    }
}

This is my function,
When the return type is &Path I get expected named lifetime parameter.
When the return type is &static Path I get returns a reference to data owned by the current function.
When the return type Path I get doesn't have a size known at compile-time.

How can I make the functionality work?

2 Answers 2

3

The problem you have here is that the Path type is a reference type. It basically points to an existing owning PathBuf.

It is a relation equivalent to what a str is to a String.

In addition, the Path::join() method returns a PathBuf (see https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.join).

The solution here is to change your return type accordingly:

use std::path::Path;
use std::path::PathBuf;

struct Deploy(PathBuf);

impl Deploy {
    fn values_yaml(self) -> PathBuf {
        let values_yaml = self.0.join("helm").join("chart").join("values.yaml");
        values_yaml
    }
}

Playground link

Sign up to request clarification or add additional context in comments.

Comments

2

Path is an unsized type, meaning that it must always be used behind a pointer like & or Box. The owned version of this type is PathBuf. PathBuf implements Deref to Path, so you can use all of its methods. This explains why you cannot return Path.
Now why can't you return &Path from your method? Have a look at join: Creates an owned PathBuf with path adjoined to self. So you create a new PathBuf in your method and return a reference to it. But this new one will be dropped as soon as the method ends and the PathBuf goes out of scope. You also currently take ownership of self, so this would drop the PathBuf even if you do not create a new one but just push to it.

So how would solutions look like? Assuming you do not want to modify the PathBuf in Deploy, you'd simply return an owned PathBuf.

use std::path::Path;
use std::path::PathBuf;

struct Deploy(PathBuf);

impl Deploy {
    fn values_yaml(&self) -> PathBuf {
        self.0.join("helm").join("chart").join("values.yaml")
    }
}

fn main() {
    let s = r"/etc";
    let deploy = Deploy(PathBuf::from(s));
    let values_yaml = deploy.values_yaml();
    i_take_a_path(&values_yaml);
}

fn i_take_a_path(path: &Path) {
    println!("{:?}", path);
}

If you really want to modify the underlying PathBuf of Deploy, you'd go with that:

use std::path::Path;
use std::path::PathBuf;

struct Deploy(PathBuf);

impl Deploy {
    fn values_yaml(&mut self) -> &Path {
        self.0.push("helm");
        self.0.push("chart");
        self.0.push("values.yaml");
        self.0.as_path()
    }
}

fn main() {
    let s = r"/etc";
    let mut deploy = Deploy(PathBuf::from(s));
    let values_yaml = deploy.values_yaml();
    i_take_a_path(values_yaml);
}

fn i_take_a_path(path: &Path) {
    println!("{:?}", path);
}

This time the reference works, because it is directly pointing to the PathBuf in Deploy, and not a newly created one.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.