Shoggomo
Shoggomo

Reputation: 137

Prevent direct initialization of type alias

I'm currently learning rust and stumbled across a problem I'm not sure how to solve.

I want to have a type (called Guess), thats just a i32 limited to a certain number range (between 1 and 100 in example below). My current solution is to use a type alias implementing a new function to enforce the number range. Still it can be created through normal initialization, without using Guess::new(), because there are no private fields like in a struct.

Can this be prevented? Also a direct change of the value should be prevented too.

Code example (playground):

type Guess = i32;

trait G {
    fn new(val: i32) -> Guess;
}

impl G for Guess {
    fn new(val: i32) -> Guess {
        if val < 1 || val > 100 {
            panic!("Only guesses between 1 and 100 are allowed!");
        }
        val
    }
}

fn main() {
    let guess: Guess = 23; // should not be allowed
    let guess: Guess = Guess::new(42); // only this should be allowed
    println!("Guess this number: {}", guess);
}

Upvotes: 2

Views: 639

Answers (2)

Acorn
Acorn

Reputation: 26136

As others have said, what you want to do is use the "newtype" pattern, which is basically wrapping your type into another:

struct Guess(i32);

impl Guess {
    fn new(val: i32) -> Self {
        assert!(val >= 1 && val <= 100,
            "Only guesses between 1 and 100 are allowed!");
        Self(val)
    }
}

fn main() {
    //let guess: Guess = 23; // this is an error now
    let guess: Guess = Guess::new(42); // fine
    println!("Guess this number: {}", guess.0);
}

The main different is that users will need to use guess.0.


A few other improvements too:

  • No need for a trait just to define methods.
  • Using Self avoids repetitions of the typename.
  • assert! for if + panic!.

Upvotes: 1

Kevin Reid
Kevin Reid

Reputation: 43782

A type never gives you any additional privacy/guarantees/invariants. What type defines is strictly an alias: "use this name as another name for this existing type". In your code as it is, Guess and i32 can be used interchangeably.

In order to implement the range restriction you want, you must define a new type (not just a new name for an existing type) using struct.

Upvotes: 1

Related Questions