Summary
Correctness should be a priority in terms of performance and correctness (for ranges such as 1-100), all solutions ( u8 , u32 , ...) are equally bad. A better solution would be to create a new type to benefit from strong typing.
The rest of my answer tries to justify this statement and discusses various ways to create a new type.
Detailed explanation
Let's look at an example of "topic evaluation": the only valid values are 0-100. I argue that correctness using u8 and u32 equally bad: in both cases, your variable may contain values that are not legal in your semantic context; This is bad!
And arguing that u8 better because there are less illegal values, it looks like fighting a bear is better than walking around New York because you have only one chance to die (blood loss by a bear attack) as opposed to many possibilities of death (car accident, knife attack, drowning, ...) in New York.
So what we want is a type that guarantees the preservation of only legal values. We want to create a new type that does just that. However, there are several ways to continue; each of which has different advantages and disadvantages.
(A) Make the internal meaning public
struct ScoreOfSubject(pub u8);
Advantage : at least the APIs are easier to understand because the parameter is already type-explained. Which is easier to understand:
add_record("peter", 75, 47) oradd_record("peter", StudentId(75), ScoreOfSubject(47)) ?
I would say the last one :-)
Disadvantage : in fact, we do not check the range, and illegal values may still occur; badly!.
(B) Make the internal value private and provide a range validation constructor
struct ScoreOfSubject(pub u8); impl ScoreOfSubject { pub fn new(value: u8) -> Self { assert!(value <= 100); ScoreOfSubject(value) } pub fn get(&self) -> u8 { self.0 } }
Advantage : we apply legal values with a very small code, yes :)
Disadvantage : working with a type can be annoying. Almost every operation requires a programmer to package and unpack a value.
(C) Add a bunch of implementations (in addition to (B))
(the code will be impl Add<_> , impl Display , etc.)
Advantage : the programmer can use this type and do all the useful operations with it directly - with a range check! This is pretty optimal.
Please take a look at Matthieu M. comment:
[...], as a rule, multiplying points together or dividing them, does not give an assessment! Strong typing not only leads to valid values, but also leads to valid actions, so you don't actually split the two counts together to get another result.
I think this is a very important point that I have not clarified before. Strong typing prevents the programmer from performing illegal operations on values (operations that make no sense). A good example is the cgmath box, which distinguishes point vectors and directions because both support different operations on them. You can find an additional explanation here .
Disadvantage : a lot of code: (
Fortunately, the flaw can be reduced by the macro / compiler plug-in system Rust. There are boxes, such as newtype_derive or bounded_integer , that do the code generation for you (disclaimer: I have never worked with them).
But now you say: "You can’t be serious? Should I spend my time creating new types?"
Not necessarily, but if you are working on production code (== at least somewhat important), then my answer is: yes, you should.