Require a field as part of a Rust trait
Asked Answered
P

2

6

Is it possible to require that a struct have a particular field as part of a trait? I am doing some web automation in Rust with the thirtyfour_sync crate. I want to write some traits with default implementations for page objects that will implement them. Basically, I know for a fact that every struct that is going to implement this trait will have a field called "driver" that holds a reference to a WebDriver struct. I want to use this driver field in my default implementation of the trait.

error[E0609]: no field `driver` on type `&Self`
  --> src\base_order_details.rs:13:30
   |
10 | / pub trait BaseOrderDetails {
11 | |
12 | |     fn oid(&self) -> WebDriverResult<String> {
13 | |         let oid_title = self.driver.find_element(By::XPath("//*[text()=\"Order ID:\"]"))?;
   | |                              ^^^^^^
...  |

Is there a way to let the compiler know that anything implementing this trait will have a field driver of type &WebDriver?

Potamic answered 29/6, 2021 at 2:31 Comment(1)
Does this answer your question? Is it possible to access struct fields from within a trait?Pahoehoe
P
4

I discovered the answer to my question while drafting it. No, you cannot access fields from traits. As a solution, I have added a get_driver method to the trait and used it within the default implementation, so the user can simply implement the get_driver method and default the rest.

pub trait BaseOrderDetails {

    fn get_driver(&self) -> &WebDriver;

    fn oid(&self) -> WebDriverResult<String> {
        let oid_title = self.get_driver().find_element(By::XPath("//*[text()=\"Order ID:\"]"))?;

        // do some other stuff

I found this solution in the Rust Book chapter on traits, under Default Implementations: https://doc.rust-lang.org/book/ch10-02-traits.html

Potamic answered 29/6, 2021 at 2:31 Comment(1)
Good answer! Yep, you're right. Some languages, such as Kotlin, allow interfaces to specify property-like values, but Rust takes the perspective that a method call should always syntactically look like a method call, and field access should always look like field access. So having a get_driver method is the exact right way to do itLayfield
N
-1

I started learning Rust and has with the same problem. but a cleaner way is think in Trait as interface. Methods in traits must be implemented to each desired struct. This in an exemple from the book Complete Rust Reference

// super_player/src/media.rs
pub trait Playable {
 fn play(&self);
 fn pause() {
  println!("Paused");
 }
}

// super_player/src/main.rs
mod media;
struct Audio(String);
struct Video(String);
impl Playable for Audio {
 fn play(&self) {
  println!("Now playing: {}", self.0);
 }
}
impl Playable for Video {
 fn play(&self) {
  println!("Now playing: {}", self.0);
 }
}

fn main(){
...
Nonintervention answered 19/2 at 17:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.