Reputation: 1762
I am trying to write a test to determine whether struct A
has a property a
and its type is i32
.
pub struct A {
a: i32,
}
#[test]
pub fn test_A() {
assert!(A.hasattr("a"));
assert_is_type!(A.a, i32);
}
Upvotes: 3
Views: 6059
Reputation: 29981
Note: This answer is insufficient in some cases. See rp123's answer for a better solution.
You can assert that a type has a property of a specific type at compile time by trying to use it in a context that requires that type:
macro_rules! assert_is_type {
($t:ty, $i:ident: $ti:ty) => {
const _: () = {
fn dummy(v: $t) {
let _: $ti = v.$i;
}
};
}
}
pub struct A {
a: i32,
}
assert_is_type!(A, a: i32);
// do not compile
assert_is_type!(A, b: i32);
assert_is_type!(A, a: i64);
Upvotes: 3
Reputation: 3643
mcarton's answer is close, but in some special cases defeated by implicit type coercions (https://doc.rust-lang.org/reference/type-coercions.html). Here is an example where it gets the field type wrong: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=dd2b2659bc75603f1bd5d0d1d34d5303.
This can be fixed by creating a modification that avoids an implicit coercion context, see playground
pub trait EqType {
type Itself;
}
impl<T> EqType for T {
type Itself = T;
}
fn ty_must_eq<T, U>(_: T) where T: EqType<Itself=U> {}
macro_rules! assert_is_type {
($t:ty, $i:ident: $ti:ty) => {
const _: () = {
#[allow(unused)]
fn dummy(v: $t) {
ty_must_eq::<_, $ti>(v.$i);
}
};
}
}
pub struct A {
a: &'static Box<i32>,
b: u32,
}
// Correctly accepted:
assert_is_type!(A, a: & Box<i32>);
assert_is_type!(A, b: u32);
// Correctly rejected:
assert_is_type!(A, a: &i32);
assert_is_type!(A, b: i32);
Upvotes: 2
Reputation: 8934
In Rust, unlike some languages like Python, the types of all values must be known at compile time. This test doesn't make sense because in order to compile the code you must already know the answer.
If a field in a struct is optional, put it in an Option
.
pub struct A {
a: Option<i32>,
}
If you have common functionality between multiple structs, make a trait for it.
pub trait ATrait {
fn get_a(&self) -> i32;
}
Upvotes: 7