Quite simply, I have a setter method on a struct that sets a field value of type i32
and I don't want to allow zero or negative numbers. I have achieved this with an assert!
macro like so:
pub fn set_myfield(&mut self, arg: i32) {
assert!(arg > 0);
self.myfield = arg;
}
This appears to cause a panic at runtime if the caller calls set_myfield(0)
, but gives no error at compile time. Is there any kind of assertion I can write so that consumers of my library will get an error at compile time if their code tries to call this method with a zero or negative input?
In Rust, there is no way to specify a subset of a type's values as a type. However, you can define new types which enforce rules, or use existing ones, and there is even an existing type for the rule you want: std::num::NonZeroI32
.
pub fn set_myfield(&mut self, arg: NonZeroI32) {
self.myfield = arg.get();
}
Now, in a sense, this doesn't change anything — there's still going to be a run-time check for constructing NonZeroI32
. However, it means that:
set_myfield
, which may simplify error handling paths.And, in future versions of Rust, it may be possible to (when applicable) define constants of nonzero types, making everything truly compile-time checked.
use std::num::NonZeroI32;
const FOUR: NonZeroI32 = NonZeroI32::new(4).unwrap();
(Right now, this code doesn't compile because Option::unwrap()
is not available in const
evaluation.)