- Earlier, we discussed that structs and enums group related data, while impl blocks and traits add associated and shared behavior to the data.
- Usage of
Selfvsselfkeywords:Self: Refers to the type itself (the blueprint).self: Refers to the instance of the type (the actual data).- ๐ฏ This can be any form of
self,&self,&mut self,self: Box<Self>,self: Pin<&mut Self>, etc.
- ๐ฏ This can be any form of
- There are multiple ways to implement a behavior for a type. We discuss only about the
implblocks with this article. The patterns involving traits are discussed under Traits.
Inherent impls
Implement associated functions, methods, and constants directly for a type.
โญ๏ธ The implementation must be in the same crate as the type.
impl Type
struct Person {
name: String,
}
impl Person {
const GREET: &str = "Hello!";
fn greet(&self) -> String { // &self` is shorthand for self: &Self
format!("{} I am {}.", Self::GREET, self.name) // ๐กSelf to access type; self to access instance
}
}
fn main() {
let steve = Person { name: "Steve".to_string() };
println!("{}", steve.greet()) // Hello! I am Steve.
}
- Inside the
implblock,- Constants belong to the type itself.
- To access them, use the
Selfkeyword or the type name. - Example:
Self::GREET(preferred in Rust) orPerson::GREET.
- To access them, use the
- Methods (functions that access instance fields) must send the instance/
selfas the first parameter.- This can be
self,&self,&mut self,self: Box<Self>,self: Pin<&mut Self>, etc.) as the first parameter.
- This can be
- Constants belong to the type itself.
impl<T> Type<T>
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn into_tuple(self) -> (T, T) {
(self.x, self.y)
}
}
fn main() {
let a = Point { x: 0, y: 1 }; // a: Point<i32>
let b = a.into_tuple(); // (0, 1)
println!("{b:?}")
}
// ๐ก into_tuple() take self (not &self) and consumes the self / instance.
// ๐ก we can pass &self (as a reference) and use as_ prefix to borrow the instance.
// fn as_tuple(&self) -> (&T, &T) { (&self.x, &self.y) }
Associated Functions & Methods
- Associated functions:
- Functions that are associated with a particular data type via the
implblock. - Can call from the type with
::operator.Person::new(),Vec::new(),String::from()
- Functions that are associated with a particular data type via the
- Methods:
- Associated functions with a receiver of
self,&self,&mut self,self: Box<Self>,self: Pin<&mut Self>, etc. - Can call from the instance with
.operator or from the type (as methods are also associated functions) with::operator, but we need to pass the instance as the first parameter always.steve.greet()orPerson::greet(&steve)"hello".to_string()orString::to_string("hello")
- Associated functions with a receiver of
struct Person {
name: String,
company_name: String,
}
impl Person {
// ๐ก The constructor (new` is a conventional name, not a keyword)
fn new(name: String, company_name: String) -> Self { // an associated function and not a method
Self { name, company_name }
}
fn intro_name(&self) -> String { // a method
format!("I'm {}", self.name)
}
fn intro_company(&self) -> String { // a method
format!("I'm from {}", self.company_name)
}
}
fn main() {
// Call from the type with `::` operator
let steve = Person::new(String::from("Steve Jobs"), String::from("Apple"));
// Call from the instance with `.` operator
println!("{}. {}.", steve.intro_name(), steve.intro_company()); // I'm Steve Jobs. I'm from Apple.
// As methods are also associated functions; Call from the type with `::` operator and pass the instance as the first parameter
println!("{}. {}.", Person::intro_name(&steve), Person::intro_company(&steve)); // I'm Steve Jobs. I'm from Apple.
}
We can use the type/ Person instead Self keyword in the new function. By the way, using the Self keyword is considered idiomatic in Rust.
fn new(name: String, company_name: String) -> Person {
Person { name, company_name }
}
๐จโ๐ซ Before going to the next…
- Familiarize with the conventional prefixes and suffixes used in methods names.
Prefix Postfix self taken self type as_ none &self or &mut self any from_ none none any into_ none self any is_ none &mut self or &self or none any to_ _mut &mut self any to_ not _mut self Copy to_ not _mut &self not Copy