Skip to main content

Command Palette

Search for a command to run...

rust :: 與 . 的差別

Updated
2 min read

閱讀 rust 程式的時候偶爾會看到 File::open() 或是 f.read()。但為什麼有些功能是用 :: 呼叫,有些是用 .

翻開 std::fs::File原始碼,可以看到這些功能都是定義在 impl File 或是 impl SomeTrait for File 內:

// src/std/fs.rs 精簡版
impl File {
    pub fn open(path: P) -> io::Result<File> {省略}
    pub fn create(path: P) -> io::Result<File> {省略}
    pub fn create_new(path: P) -> io::Result<File> {省略}

    pub fn metadata(&self) -> io::Result<Metadata> {省略}
}
impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {省略}
}
impl Write for File {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {省略}
}

impl File 或是 impl Read for File 都是在給 File struct 加功能。但既然都是給 File 用,為什麼呼叫方式不一樣?

:: 的使用情境

  1. 使用 (access) struct 的相關功能 (associated functions)

  2. 使用 (access) 套件 (crate) 或是模組 (module) 內的功能 。這個之後會再解釋

什麼是相關功能 (associated functions)?

Associated function 可以被看作是操作 struct 的功能,例如 File::open()File::create() 都會產生一個新的 File 物件 (嚴格來說是一個 Result enum 包著的 File 物件) 。 有些語言把這種功能稱為 static method 。

只要是呼叫相關功能一律都是用 ::

最常見的 associated function 就是 new() , 用來產生一個新的物件並初始化它的內部值。

// 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();
}

把給 Cat 用的功能與方法都放在 impl Catimpl SomeTrait for Cat 區塊內讓讀者很容易地知道這些功能都是跟 Cat 有關。

. 的使用情境

另一方面, . 是呼叫物件方法 (method) 對物件本身操作。它們定義的第一個參數一定都是 self 。 這點跟其他語言的物件方法一致。

只要是呼叫方法一律都是用 .

例如 f.read()f.write()

use std::fs::File;
let f = File::open("myfile.txt");
f.read(); // <-- 呼叫 f 物件的方法

在解釋 :: 提到的另一個使用情境就是呼叫一個 crate 或 module 內的功能,例如 io::copy() 。這類功能並不隸屬任何 struct ,而是一個模組內的通用功能。

翻開 io::copy()原始碼,可以看到 copy() 位於 src/std/io/ 路徑的 copy.rs 模組內:

// src/std/io/copy.rs 精簡
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>

所以要用 copy 的話就需要 use std::io; 或是 use std::io::copy; 把它匯進來用:

use std::io;
io::copy(r, w);

// or

use std::io::copy;
copy(r, w);

可以看到用 use keyword 的時候也是用 :: 來指定要用的模組。 :: 在這的作用幾乎跟路徑的 / 一樣。

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