rust :: 與 . 的差別
閱讀 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
用,為什麼呼叫方式不一樣?
::
的使用情境
使用 (access) struct 的相關功能 (associated functions)
使用 (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 Cat
或 impl 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 的時候也是用 ::
來指定要用的模組。 ::
在這的作用幾乎跟路徑的 /
一樣。