Rust is statically typed language, they say. All the types are known at compilation time, they say.
That's not quite true, and I'd like to demonstrate counterexamples!
Functions working on slices (arrays of unknown size)
fn foo(arr: &mut [usize]) {
arr[arr.len() - 1] += arr[0];
}
fn main() {
let mut v: [usize; 4] = [7, 5, 1, 3];
foo(&mut v);
println!("{v:?}"); // [7, 5, 1, 10]
}
As an example, I'll use a function that adds value of first array element to the last one. Note that it takes &mut [usize]
- thing called "slice", which doesn't have length indication at all!
If you change length of array v
(suitably adding or removing elements in brackets), function foo
will be able to process it just as well. Thus, it can be said that foo
works on values of different types!
Functions on trait objects
use std::any::Any;
fn foo(something: &dyn Any) -> &'static str {
if something.is::<char>() {"char"} else {"not-char"}
}
fn main() {
println!("1: {}", foo(&1)); // 1: not-char
println!("'k': {}", foo(&'k')); // 'k': char
}
Any
is an interesting Rust trait, implemented by almost all types. It allows you to store references to values of different type in a single container, and then to check if value has a certain type.
Why not all types implement Any?
Any depends on all types having unique IDs. References (and, by extension, types containing references) are bounded by lifetimes, which are hard to put into numbers.
But perhaps the most interesting fact is that you can pass reference to a certain object (for instance, 1 of usize
) to foo
, it will automatically convert to reference to dyn Any
, and the code will compile!
There is also What is '&dyn Any', is there '&Any' as well?
dyn Trait
represents an object of some type - unknown at compilation time, but certainly implementing Trait
. Those objects may have different sizes and thus cannot be stored normally (passed to function or returned, as well). They must be behind a "smart pointer" - reference or Box
, for instance.
impl Trait
, representing object of type known at compilation time that implements Trait
as well. They may be used without restrictions.
fn maybe_max(a: impl Into<usize>, b: impl Into<usize>) -> usize {
std::cmp::max(a.into(), b.into())
}
In next post, I'll describe how Rust works with this dynamic typing in more details!
Top comments (0)