// Struct struct Point { x: i32, y: i32, } let origin: Point = Point { x: 0, y: 0 }; // A struct with unnamed fields, called a ‘tuple struct’ struct Point2(i32, i32); let origin2 = Point2(0, 0); // Basic C-like enum enum Direction { Left, Right, Up, Down, } let up = Direction::Up; // Enum with fields enum OptionalI32 { AnI32(i32), Nothing, } let two: OptionalI32 = OptionalI32::AnI32(2); let nothing = OptionalI32::Nothing; // Generics // struct Foo { bar: T } // // This is defined in the standard library as `Option` enum Optional { SomeVal(T), NoVal, } // Methods // impl Foo { // Instance methods take an explicit `self` parameter. // Using `self` on its own will consume the caller, while // `&self` or `&mut self` will create immutable and mutable // references, respectively. fn get_bar(self) -> T { self.bar } // Static methods don't take a `self` parameter, but can still // use the generic `T` type. fn do_baz(msg: &str, baz: T) -> T { println!("{}", msg); baz } } // Here `T` is inferred to be some integer type let a_foo = Foo { bar: 1 }; println!("{}", a_foo.get_bar()); // 1 // `T` can be whatever you want, using "turbofish" syntax // The statement below prints "Hello" and sets `result` to 24 let result: i32 = Foo::::do_baz("Hello", 24); // Traits (known as interfaces or typeclasses in other languages) // trait Frobnicate { fn frobnicate(self) -> Option; } impl Frobnicate for Foo { fn frobnicate(self) -> Option { Some(self.bar) } } let another_foo = Foo { bar: 1 }; println!("{:?}", another_foo.frobnicate()); // Some(1)