rust :: vs .
When reading rust codes, you sometimes see File::open or f.read(). Why are some functions accessed with ::, and others with .?
By taking a look at the source code for std::fs::File, we could see that these functions are defined either in impl File, or impl SomeTrait for File:
// src/std/fs.rs snippet
impl File {
pub fn open(path: P) -> io::Result<File> {snip}
pub fn create(path: P) -> io::Result<File> {snip}
pub fn create_new(path: P) -> io::Result<File> {snip}
pub fn metadata(&self) -> io::Result<Metadata> {snip}
}
impl Read for File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {snip}
}
impl Write for File {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {snip}
}
Either impl File or impl SomeTrait for File adds functions to the File struct, but why are they accessed differently?
When to use ::
accessing a struct's associated functions
accessing a crate or a module's functions. we'll come back to this later
What's an associated function?
An associated function is a function that operates on the struct. For example, both File::open() and File::create() return a new File instance (technically a File instance wrapped in a Result enum). Some languages call these functions static methods.
Associated functions are always accessed with a ::.
The most common example is the new() function that creates a new instance and initializes its member values:
// A struct about Cats.
struct Cat {
name: String,
age: u8,
}
impl Cat {
// An associated function to create a new cat.
fn new() -> Cat {
Cat{
name: String::from("notadog"),
age: 0,
}
}
}
fn main() {
// Call the associated function to birth a new cat instance.
let mycat = Cat::new();
}
Placing functions in impl Cat or impl SomeTrait for Cat makes obvious to anyone reading the code the relationship between the function and Cat.
When to use .
On the other hand, . is how you access instance methods. These methods operate on the instance (or object). These methods' first argument is always self. This is identical to many other languages that support object-oriented programming.
Examples include f.read(), f.write():
use std::fs::File;
let f = File::open("myfile.txt");
f.read(); // <-- calling `read` method on instance `f`
Another scenario that uses :: is to access items in a crate or module. For example, io.copy() does not belong to any struct, it's a function defined in the std::io module.
Take a look at the source code for io::copy(), you'll see copy.rs module located under src/std/io:
// src/std/io/copy.rs snippet
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
To access copy(), you'd need to use std::io; or use std::io::copy; to bring it into scope:
use std::io;
io::copy(r, w);
// or
use std::io::copy;
copy(r, w);
As you can see, the use keyword also uses :: to locate io module in std crate. Here :: behaves almost like / in a path.