Trait Bounds
Trait bounds constrain generic type parameters so a function can call trait methods on values of unknown type. The syntax <T: TraitName> means "this function works for any type T that implements TraitName".
Code
// Trait bounds: función genérica que acepta cualquier tipo con Display
trait Display {
fn to_string(self) -> String
}
struct Point {
x: int,
y: int
}
impl Display for Point {
fn to_string(self) -> String {
return "(" + int_to_string(self.x) + ", " + int_to_string(self.y) + ")"
}
}
struct Circle {
radius: int
}
impl Display for Circle {
fn to_string(self) -> String {
return "Circulo{radio=" + int_to_string(self.radius) + "}"
}
}
fn print_it<T: Display>(x: T) -> String {
return x.to_string()
}
fn show_twice<T: Display>(x: T) {
let s: String = x.to_string()
print(s)
print(s)
}
fn main() -> int {
let p: Point = Point { x: 7, y: 2 }
print(print_it<Point>(p))
let c: Circle = Circle { radius: 10 }
print(print_it<Circle>(c))
show_twice<Point>(p)
return 0
}
Output
(7, 2)
Circulo{radio=10}
(7, 2)
(7, 2)
Explanation
print_it<T: Display> is a generic function that accepts any type T as long as it implements Display. The bound T: Display tells the compiler two things: it may generate a specialized version for each concrete type used at the call site (monomorphization), and it guarantees that x.to_string() is always a valid call inside the function body.
show_twice demonstrates that trait-bounded generics are ordinary functions — they can hold local variables, call the trait method multiple times, and produce any side effects. The compiler produces separate machine-code versions for Point and any other type you pass, so there is zero virtual dispatch overhead.
At the call site, the type argument is written explicitly as print_it<Point>(p). Nyx can often infer the type argument, but being explicit is always valid and sometimes clearer when reading code.