DEV Community

Cover image for What This Senior Developer Learned From His First Big Rust Project

What This Senior Developer Learned From His First Big Rust Project

Andrew (he/him) on January 09, 2024

cover photo by Pixabay Here is a bit of background on me according to my company's org chart on Workday, my current title is "Senior Consul...
Collapse
 
gsnoff profile image
Ilyas Gasanov • Edited

You can also use S: AsRef<str> (or s: impl AsRef<str>) if you don’t need the String ownership within the function code. It’s just as common and ergonomic, and it saves on performance too. The only downside is that it doesn’t support Display/ToString types which don’t contain immediate string data.

Ideally, it should’ve been possible to define a custom trait with a function which returns a Cow<'a, str>, and provide blanket implementations for all types that a) implement AsRef<str> (returning Cow::Borrowed(str)), and b) implement Into<String> but do not implement AsRef<str> (returning Cow::Owned(String)). Alas, Rust currently doesn’t support custom generic specializations or non-union trait/type guard operators, since it’s a huge headache to do such features in a sound way, so that they cannot break SemVer guarantees after landing.

Collapse
 
awwsmm profile image
Andrew (he/him)

What's the benefit to using s: impl AsRef<str> over s: &str?

I asked myself the above and then found this message board thread from 2016: users.rust-lang.org/t/idiomatic-st...

...seems this is not a new discussion we're having.

Collapse
 
rsalmei profile image
Rogério Sampaio de Almeida • Edited

Hey, you're mistaken about get_handler(). Let me try to explain it.
When a trait declares this:

pub trait Sensor: Device {
    fn get_handler(&self) -> Handler {
        // some default implementation here for all `Sensor`s
    }
}
Enter fullscreen mode Exit fullscreen mode

It is NOT providing a default implementation of the Device trait method with the same name. The declaration "trait Sensor: Device" only says that in order to implement Sensor, an entity must also implement Device. This means that fn get_handler() from Sensor has NOTHING to do with fn get_handler() from Device! They are two entirely distinct methods.

So, there isn't any information missing that the compiler could fill in. Your struct does have BOTH methods available. You can even disambiguate them and call whichever you want: given a ts variable with a TemperatureSensor, you can call both Sensor::get_handler(&ts) and Device::get_handler(&ts).
That's why you need to implement the Device trait, and in there, it is your call whether you reuse the other method with the same name or not.