side = "6"radius = "3"// TOUR: generics and traits//// The subject is what the debugger shows you when the source is written once// and executed several times over different types. A generic function has one// body and many instantiations; a trait method has one name and many bodies.// Both are places where "which code is running" is a real question, and the// call trace is where it gets answered.mod shapes;use shapes::{Circle, Rect, Shape};// A type generic. One body, three instantiations — `u32`, `u64` and `i32` —// and the call trace names the frame each time it is entered.//// The bound is `Ord`, which `Field` deliberately does NOT implement: field// elements wrap, so "greater than" is not a question they answer. That refusal// is a language fact worth meeting here rather than in a compiler error later.unconstrained fn largest<T>(a: T, b: T) -> Twhere T: std::cmp::Ord,{ if a > b { a } else { b }}// A NUMERIC generic: `N` is a value, not a type, and the same source runs over// arrays of two different lengths. The loop bound is the generic, so the loop// rail has a different number of rungs per instantiation.unconstrained fn sum_all<let N: u32>(values: [u32; N]) -> u32 { let mut total: u32 = 0; for i in 0..N { total = total + values[i]; } total}// A generic constrained by a trait this package defines. Which `area` runs is// decided by the argument's type, and the only place a reader can SEE which// one ran is the trace.unconstrained fn describe<T>(shape: T) -> u32where T: Shape,{ let a = shape.area(); let p = shape.perimeter(); a + p}unconstrained fn main(side: u32, radius: pub u32) -> pub u32 { // Three instantiations of one generic function, over three types. let big_u = largest(side, 17); let big_w = largest(side as u64, 4_000_000_000); // The suffix is load-bearing: a bare negative literal is a `Field`, and // `Field` has no `Ord`. let big_i = largest(-3_i32, -9_i32); // Two instantiations of a numeric generic, N = 3 and N = 5. let three = sum_all([1, 2, 3]); let five = sum_all([side, side, side, side, side]); // Two impls of one trait, dispatched by type. let c = describe(Circle { radius }); let r = describe(Rect { w: side, h: side + 1 }); assert(big_u >= 17); assert(three == 6); assert(big_i == -3); assert(big_w == 4_000_000_000); big_u + three + five + c + r + big_w as u32}// A trait with two implementations, in a module of its own so that stepping// into a trait method crosses a file boundary and the call trace has to name// which impl it entered — the thing a source view alone cannot tell you.pub trait Shape { fn area(self) -> u32; // A DEFAULT method: `Circle` takes it as written and `Rect` overrides it, // so the same call spelling reaches two different bodies and the trace is // what distinguishes them. fn perimeter(self) -> u32 { self.area() * 2 }}pub struct Circle { pub radius: u32,}pub struct Rect { pub w: u32, pub h: u32,}impl Shape for Circle { fn area(self) -> u32 { // 3 is a deliberately crude pi: this program is about dispatch, and a // value a reader can verify in their head is worth more here than a // correct one they cannot. 3 * self.radius * self.radius } // `perimeter` is NOT overridden — the default body runs.}impl Shape for Rect { fn area(self) -> u32 { self.w * self.h } fn perimeter(self) -> u32 { 2 * (self.w + self.h) }}[package]name = "tour_generics"type = "bin"authors = ["BlockTracer capability tour"][dependencies]