Skip to main content

Command Palette

Search for a command to run...

rust :: vs .

Updated
3 min read

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 ::

  1. accessing a struct's associated functions

  2. 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.

More from this blog

Ai與知識債

技術債 technical debt 源自貪快/便宜/方便而採用的技術方案,犧牲可讀性、維護性、測試性、文件完整等等的面向,延後償還技術上的代價 隨著 vibe coding 的普及,另一種債也在慢慢累積:知識債 開發者抱著一個「可以跑就好」的想法就把產品推上架,卻不理解 AI 生成的程式碼到底在做什麼、不知道 AI 的作法到底對不對。前一陣子的鏟子英雄平台個資問題就是案例之一 哈佛教授 Jonathan Zittrain 已經在 2019 年將此現象取名為 intellectual debt,...

Jan 8, 20261 min read

結巴分詞解析三部曲, 第三集

How jieba works, part 3 本篇將用 Part 2 介紹的隱藏式馬可夫模型與 Viterbi 演算法將剩下的字 (大、學、與、老、師、討、論、力、學) 分詞。 字的隱藏狀態 一個人的身體可以有健康、生病的隱藏狀態。那一個字可以有幾種?結巴的程式碼定義了四種隱藏狀態:詞首、詞中、詞尾、以及單獨存在,分別用 B, M, E, S 標示。這四種狀態其實就是字位於詞的不同位置。 例如: 我: S 『我』只有一個字,所以標示 S 單獨存在。 的: S 『的』只有一個字,所以標示...

Aug 19, 20229 min read

結巴分詞解析三部曲, 第二集

How jieba works, part 2 這篇將解釋何謂馬可夫模型 Markov model、隱藏式馬可夫模型 Hidden Markov model (HMM)、與 Viterbi 演算法。 馬可夫模型 Markov model 馬可夫模型是一個用來解釋偽隨機系統的模型。它假設未來事件只受到現在事件影響,不受更早事件影響。 範例:假設你是醫生,從你的臨床經驗來看,一個人身體前一天健康、今天也健康的機率是 0.7;前一天健康、今天生病的機率是 0.3;前一天生病、今天健康的機率是 0.4;...

Aug 19, 20223 min read

Blank Stare

9 posts