How do I reuse code for similar yet distinct types in Rust?

前端 未结 2 361
情书的邮戳
情书的邮戳 2021-01-27 19:09

I have a basic type with some functionality, including trait implementations:

use std::fmt;
use std::str::FromStr;

pub struct MyIdentifier {
    value: String,
         


        
2条回答
  •  面向向阳花
    2021-01-27 19:25

    Use a PhantomData to add a type parameter to your Identifier. This allows you to "brand" a given identifier:

    use std::{fmt, marker::PhantomData, str::FromStr};
    
    pub struct Identifier {
        value: String,
        _kind: PhantomData,
    }
    
    impl fmt::Display for Identifier {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.value)
        }
    }
    
    impl FromStr for Identifier {
        type Err = ();
    
        fn from_str(s: &str) -> Result {
            Ok(Identifier {
                value: s.to_string(),
                _kind: PhantomData,
            })
        }
    }
    
    struct User;
    struct Group;
    
    fn main() {
        let u_id: Identifier = "howdy".parse().unwrap();
        let g_id: Identifier = "howdy".parse().unwrap();
    
        // do_group_thing(&u_id); // Fails
        do_group_thing(&g_id);
    }
    
    fn do_group_thing(id: &Identifier) {}
    
    error[E0308]: mismatched types
      --> src/main.rs:32:20
       |
    32 |     do_group_thing(&u_id);
       |                    ^^^^^ expected struct `Group`, found struct `User`
       |
       = note: expected type `&Identifier`
                  found type `&Identifier`
    

    The above isn't how I'd actually do it myself, though.

    I want to introduce two types which have the same fields and behaviour

    Two types shouldn't have the same behavior — those should be the same type.

    I don't want to copy the entire code I just wrote, I want to reuse it instead

    Then just reuse it. We reuse types like String and Vec all the time by composing them as part of our larger types. These types don't act like Strings or Vecs, they just use them.

    Maybe an identifier is a primitive type in your domain, and it should exist. Create types like User or Group and pass around (references to) users or groups. You certainly can add type safety, but it does come at some programmer expense.

提交回复
热议问题