0

I have some code, but the problem boilds down to this:

pub struct Thing<S>
where S: AsRef<str> // im using AsRef here but the point is just that `S` is string-like
{
   this: S
}

impl<S> Default for Thing<S>
where S: AsRef<str> {
    fn default() -> Self {
        Self {
            this: "i am a `&'static str`"
        }
    }
}

Cargo says:

expected type parameter `S`
        found reference `&'static str`

I get that the problem is something to do with it being a reference to an str, I just don't really know what to do about it. How do I restrict a generic to being "string like", while making sure that said generic can be at least an &str or a String?

salmon
  • 31
  • 4
  • The main question is: What should `Thing::default` return? Writing this would be allowed in your current code, but the `this` value would clearly not be a `String` because it internally gets instantiated with a `&'static str`. I feel like this is an XY-problem, and what you actually want is an enum. Although I'm of course missing context, so I don't know. – Finomnis May 19 '23 at 22:32
  • @Finomnis the general idea is a config for the lib, one of the values being a "name" which I want to be some kind of string. The default implementation will just return what I think are sensible defaults for people who don't want to fill all the values (there are a lot) – salmon May 19 '23 at 22:50
  • Be aware that the actual type of the generic is determined at **compile time**. I'm not sure using a generic here is the right choice. You won't ever be able to use the default unless you specify at the struct where you are using it that it will be a `Thing<&'static str>`, and then it will no longer accept anything else than a `&'static str` ever again. Are you sure this is what you want? – Finomnis May 19 '23 at 23:24

2 Answers2

4

In this situation, you don't want a generic at all. The function doesn't produce a generic Self, it produces a specific one.

impl Default for Thing<&'static str> {
    fn default() -> Self {
        Self {
            this: "i am a `&'static str`"
        }
    }
}

Also, don't put trait bounds on struct definitions.

drewtato
  • 6,783
  • 1
  • 12
  • 17
  • Generally I don't do trait bounds on struct definitions but this struct is intended to be built manually so I can't restrict it from a function – salmon May 19 '23 at 22:44
  • 2
    @salmon It is still not necessary unless it implements `Drop`. There is no harm in creating something that can't be used. – drewtato May 19 '23 at 22:58
0

To avoid future problems with the lifetime, you can also solve the task by using String instead of &str:

pub struct Thing<S: Into<String>> {
    this: S,
}

impl Default for Thing<String> {
    fn default() -> Self {
        Self {
            this: "I am a String".to_string(),
        }
    }
}
Kaplan
  • 2,572
  • 13
  • 14