Rust 包與模塊系統(tǒng) --- Packge Crate 與 Module 解惑

Rust 對于我是一門反復(fù)入門的語言凛辣。每當(dāng)我以為自己入門了毅哗,過了一段時間又會發(fā)現(xiàn)之前理解的不準(zhǔn)確听怕。
其中有一個原因就是 Rust 中的一些概念,與其他編程語言對比的時候虑绵,經(jīng)常似是而非尿瞭。即其他語言也有類似的概念,但是只是相似翅睛,并不能看成一致声搁。
很多人在學(xué)習(xí) Rust 的時候,會下意識跟自己其他語言的經(jīng)驗類比宏所。如 cargo 和 pip酥艳,use 和 import摊溶,trait 和 interface 爬骤,crate 和 package 等等。但是這些內(nèi)容 rust 都有自己獨立的特性莫换。我猜 Rust 把這些相似的概念使用了新名詞霞玄,大概也是讓學(xué)習(xí)者不要輕易的當(dāng)成一回事。
本文就 rust 的代碼組織方式進(jìn)行介紹拉岁,主要說明 crate 和 module 的關(guān)系坷剧。

何為Crate


Package CrateModuleRust 組織代碼的方式。其中 package 和 module 比較好理解喊暖,大多數(shù)編程語言都有類似的概念惫企。
package 譯為,一個用于構(gòu)建陵叽、測試并分享的 Cargo 功能狞尔,簡而言之就是一個 cargo 項目就是一個 package。module 譯為模塊巩掺,用于組織代碼結(jié)構(gòu)和訪問性的功能塊偏序,可以類別其他語言的命名空間(namespace)。
然而 crate 是 rust 特有的名詞胖替,通常譯為單元包研儒。介于 package 和 module 之間的。

A crate is the smallest amount of code that the Rust compiler considers at a time
---《The Rust Programming Language》

上面這句話直譯:Crate 是 Rust 編譯器(編譯)考量的最小代碼單元独令。
如何理解這句話呢端朵?
我們回想一下C語言和編譯(匯編)過程。通常一個從一個 .c 源代碼文件到一個可執(zhí)行的二進(jìn)制文件a.out燃箭,需要經(jīng)過步驟:預(yù)處理 --> 編譯 --> 匯編 --> 鏈接 這幾個步驟逸月。

image.png
  • 預(yù)處理:將 .c代碼文件的 include 語句處理,把多個相關(guān)的文件匯聚成一個文件.i
  • 編譯:將 .i文件編譯成.s匯編文件
  • 匯編:將.s匯編文件通過匯編器匯編成目標(biāo)文件 .o o 表示object遍膜。
  • 鏈接:將多個.o文件匯聚成一個二進(jìn)制可執(zhí)行文件a.out

如何理解鏈接呢碗硬?
這其實是代碼組織的一種方式瓤湘,每個 c 文件編譯成 o 文件的時候,都是想象自己獨立使用內(nèi)存恩尾,比如都從0地址開始分配使用內(nèi)存弛说,當(dāng)匯編成一個可執(zhí)行文件的時候,需要鏈接器對他們重新排列翰意,不然內(nèi)存就沖突了木人。

例如,學(xué)屑脚迹考試后需要年級排序醒第。班級內(nèi)部也有排名。班級內(nèi)部的排名類似編譯匯編进鸠,從1開始稠曼。然后學(xué)校再按照年級排序,班級第一的同學(xué)客年,未必是年級第一霞幅。這個重排匯總的過程就類似鏈接。只不過是按照班級為單位重排量瓜。
理解了鏈接之后司恳,我們再來考慮 crate 為最小代碼單元。其本質(zhì)是指 crate 是最小的編譯單元绍傲。因此也有書翻譯為單元包扔傅。
最小編譯單元就類似上圖的一組.h.c文件,最終編譯出來的是.o文件烫饼,一個crate猎塞,就類似一個目標(biāo)文件,只不過在 rust 里枫弟,一個 crate 可以有多個.rs文件組合邢享。

Crate的種類


crate 有兩種類型,bianry crate(二進(jìn)制 crate ) 和 lib crate(庫 crate )淡诗。前者會編譯生成二進(jìn)制可執(zhí)行文件骇塘,后者編譯成不可執(zhí)行的二進(jìn)制文件。一個 package 下的 crate 規(guī)則:

  • 一個 package 至少包含一個 crate(binary crate或 lib crate)
  • 一個 package 可以包含任意多個 binary crate
  • 一個 package 至多包含一個 lib crate

Golang 里也有 可執(zhí)行包和庫包的差別

Binary Crate

crate 中包含 main函數(shù)的就是 binary crate韩容。即所有 rust 文件最后編譯成一個可執(zhí)行的二進(jìn)制文件款违,入口是main 函數(shù)。
cargo 默認(rèn)創(chuàng)建的項目群凶,src/main.rs 是 binary crate插爹,main.rs 是 crate 的根(root),該 crate 默認(rèn)的名字是 cargo.toml 里 package 里定義的 name。
下面使用代碼逐步說明 crate 和 bianry crate 的具體含義

新建package 和 crate

使用cargo new可以新建一個 package,按照一個 package 至少一個 crate 的規(guī)則赠尾,cargo 默認(rèn)生成一個bianry crate力穗。

?  rust cargo new hello
     Created binary (application) `hello` package
?  rust cd hello
?  hello git:(master) ? tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
?  hello git:(master) ? cat Cargo.toml
[package]
name = "hello"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
?  hello git:(master) ? cat src/main.rs
fn main() {
    println!("Hello, world!");
}

上面創(chuàng)建了一個包,包名是hello气嫁,rust 默認(rèn)在 src 生成了一個 main.rs 文件当窗,該文件是一個 binary crate,crate 名也是 hello

運行

使用 cargo run 可以編譯運行項目寸宵,編譯的是默認(rèn)的 bianry carte崖面,crate 名為hello的 main.rs 文件,最終生成一個可執(zhí)行的二進(jìn)制文件梯影∥自保可以使用 --bin參數(shù)指定 binary crate,不指定就是默認(rèn)的 crate甲棍。等價于cargo run --bin hello简识。其中 hello 是默認(rèn)的 crate。

?  hello git:(master) ? cargo run
   Compiling hello v0.1.0 (/Users/master/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 3.69s
     Running `target/debug/hello`
Hello, world!
?  hello git:(master) ? tree -C -L 3
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        ├── examples
        ├── hello
        ├── hello.d
        └── incremental

7 directories, 6 files
?  hello git:(master) ? ./target/debug/hello
Hello, world!

由此可見救军,cargo run其實有兩個過程:

  • 編譯:使用cargo build進(jìn)行編譯構(gòu)建财异,生成 target 目錄
  • 運行:執(zhí)行編譯的二進(jìn)制可執(zhí)行文件倘零,執(zhí)行 target/debug/hello

對于接下來的例子唱遭,為了清楚看到編譯的結(jié)果,每次編譯運行之前呈驶,都刪除上一次編譯生成的 target 文件夾

多個 bianry crate

前文提及拷泽,既然一個 package 可以包含任意多個 binary crate。表示一個 binary crate 是入口有 main 函數(shù)袖瞻,因此我們可以再幾個 binary crate司致。新建 bar.rs foo.rs 與 main.rs 同級。

?  hello git:(master) ? tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── bar.rs
    ├── foo.rs
    └── main.rs

1 directory, 5 files
?  hello git:(master) ? cat src/foo.rs src/bar.rs
fn main() {
    println!("Hello, foo!");
}
fn main() {
    println!("Hello,bar!");
}

運行 cargo run 不指定就是默認(rèn)的 binary crate聋迎。

?  hello git:(master) ? cargo run
   Compiling hello v0.1.0 (/Users/master/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 2.70s
     Running `target/debug/hello`
Hello, world!
?  hello git:(master) ? cargo run --bin hello
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hello`
Hello, world!

由于我們新增了 bar 和 foo 兩個新的 bianry crate脂矫,可以運行這兩個 bianry crate

?  hello git:(master) ? cargo run --bin bar
error: no bin target named `bar`.
Available bin targets:
    hello

?  hello git:(master) ? cargo run --bin foo
error: no bin target named `foo`.
Available bin targets:
    hello

可是事與愿違,編譯器反饋沒有找到 bar 和 foo 兩個目標(biāo) crate霉晕。同時提示了庭再,只有 hello 這個 crate。這里rust有規(guī)定牺堰,binary crate 可以有多個拄轻,但是需要組織在 src/bin 目錄下。編譯器才能搜索伟葫。下面我們調(diào)整一下代碼

?  hello git:(master) ? tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── bin
    │   ├── bar.rs
    │   └── foo.rs
    └── main.rs

2 directories, 5 files
?  hello git:(master) ? cargo run
error: `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key.
available binaries: bar, foo, hello

再次執(zhí)行 cargo run會報錯恨搓,原因是 cargo 不知道需要執(zhí)行哪一個 bianry crate,并且也提供了 bar foo hello 三個crate 可選。

按照之前的經(jīng)驗斧抱,不指定應(yīng)該是默認(rèn)的常拓,此時rust又報不知道哪一個,挺奇怪的辉浦。

我們指定 crate墩邀,然后分別查看編譯的目標(biāo)文件

?  hello git:(master) ? cargo run --bin hello
   Compiling hello v0.1.0 (/Users/master/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 2.86s
     Running `target/debug/hello`
Hello, world!
?  hello git:(master) ? tree -C -L 3
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── bin
│   │   ├── bar.rs
│   │   └── foo.rs
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        ├── examples
        ├── hello
        ├── hello.d
        └── incremental

8 directories, 8 files

只有target/debug/hello可執(zhí)行文件。

?  hello git:(master) ? rm -rf target
?  hello git:(master) ? cargo run --bin bar
   Compiling hello v0.1.0 (/Users/master/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 2.82s
     Running `target/debug/bar`
Hello,bar!
?  hello git:(master) ? tree -C -L 3
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── bin
│   │   ├── bar.rs
│   │   └── foo.rs
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── bar
        ├── bar.d
        ├── build
        ├── deps
        ├── examples
        └── incremental

8 directories, 8 files
?  hello git:(master) ? ./target/debug/bar
Hello,bar

從上面的結(jié)果來看盏浙,指定運行 bar 眉睹,bar 會被編譯,并且運行。指定 foo 的結(jié)果也一樣氮双,foo crate 會被編譯敛劝。
對于多個crate存在的情況,可以使用 cargo build一次性編譯所有的crate斋配,如果 crate 沒有代碼改動,不會重新編譯灌闺。這就避免了多個 binary crate艰争,需要多次編譯的情況了。

?  hello git:(master) ? cargo build
   Compiling hello v0.1.0 (/Users/master/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 3.27s
?  hello git:(master) ? tree -C -L 3
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── bin
│   │   ├── bar.rs
│   │   └── foo.rs
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── bar
        ├── bar.d
        ├── build
        ├── deps
        ├── examples
        ├── foo
        ├── foo.d
        ├── hello
        ├── hello.d
        └── incremental

8 directories, 12 files

對于沒有構(gòu)建依賴工具的 C 和 C++ 桂对,需要借助 Makefile 或 CMake 來處理依賴

Lib Crate

所謂 lib crate甩卓,就是沒有 main 入口函數(shù)的 crate。一個包只有一個 lib crate蕉斜,其實就是與 src 下有一個 lib.rs 文件逾柿,這個文件就是 lib crate。

?  hello git:(master) ? tree
.
├── Cargo.lock
├── Cargo.toml
└── src
    ├── bin
    │   ├── bar.rs
    │   └── foo.rs
    ├── lib.rs
    └── main.rs

2 directories, 6 files
?  hello git:(master) ? cat src/lib.rs

fn hello_lib(){
    println!("hello lib");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        hello_lib()
    }
}

執(zhí)行 cargo build 可以看到宅此,生成的 target/debug 的文件中机错,多了一個libhello.d的中間文件,這就是 lib crate 的編譯形成的目標(biāo)文件父腕,名字默認(rèn)就是 lib + package-name

?  hello git:(master) ? cargo build
   Compiling hello v0.1.0 (/Users/master/rust/hello)
warning: function `hello_lib` is never used
 --> src/lib.rs:2:4
  |
2 | fn hello_lib(){
  |    ^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `hello` (lib) generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 4.07s
?  hello git:(master) ? tree -C -L 3
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── bin
│   │   ├── bar.rs
│   │   └── foo.rs
│   ├── lib.rs
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── bar
        ├── bar.d
        ├── build
        ├── deps
        ├── examples
        ├── foo
        ├── foo.d
        ├── hello
        ├── hello.d
        ├── incremental
        ├── libhello.d
        └── libhello.rlib

8 directories, 15 files

lib.rs 文件中的代碼弱匪,出現(xiàn)了 mod 的聲明,這是 rust 模塊的聲明璧亮。就行一個package里可以有多個 crate萧诫,一個crate 里可以有多個 module

模塊


crate 是編譯最小化單元。真實的項目杜顺,代碼會按照其功能性進(jìn)行模塊化财搁。rust 的模塊系統(tǒng)很強大,但是跟其他語言有一點點差別躬络,模塊系統(tǒng)和文件系統(tǒng)是相對獨立尖奔。這一點跟其他編程語言完成不同。
簡而言之,其他編程語言的文件系統(tǒng)和模塊系統(tǒng)是高度一致提茁。文件系統(tǒng)的目錄樹和模塊的目錄差不不大淹禾。rust 獨樹一幟,即可以跟文件系統(tǒng)一樣組織茴扁,也可以獨立成為一個文件铃岔。
為了簡單起見,我們先在一個文件里介紹模塊系統(tǒng)峭火,然后再結(jié)合文件系統(tǒng)組織進(jìn)行說明毁习。

模塊聲明

以 《rust 權(quán)威指南》 里的例子說明,有這樣一個crate卖丸,其模塊組織如下:

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
 

使用 cargo 新建一個 demo 項目纺且。main.rs 文件如下:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("add_to_waitlist");
        }

        pub fn seat_at_table() {
            println!("seat_at_table");
        }
    }
    pub mod serving {
        pub fn take_order(){
            println!("take_order");
        }

        pub fn serve_order(){
            println!("serve_order");
        }

        pub fn take_payment(){
            println!("take_payment");
        }
    }
}


fn eat_at_restaurant() {
    println!("eat_at_restaurant");
}


fn main() {

    eat_at_restaurant();
    crate::front_of_house::hosting::add_to_waitlist();
}

為了先說明模塊系統(tǒng),所有模塊和函數(shù)都定義 pub(可導(dǎo)出)稍浆。
從上上面的代碼可以看到

  • rust 使用 mod 和花括號聲明模塊
  • 模塊可以嵌套
  • 模塊內(nèi)可以包含其他條目的定義载碌,比如結(jié)構(gòu)體、枚舉衅枫、常量嫁艇、trait或函數(shù)
  • 模塊的邏輯都可以組織在一個文件里,獨立與文件系統(tǒng)

模塊與文件系統(tǒng)

通過 mod可以組織模塊弦撩。然而我們更熟悉的是使用文件系統(tǒng)步咪。例如上面的模塊目錄樹,我們更熟悉文件系統(tǒng)孤钦。理想狀態(tài)如下:

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
?  src git:(master) ? tree
.
├── front_of_house
│   ├── hosting.rs
│   └── saving.rs
└── main.rs

0x00

下面我們逐步創(chuàng)建這樣的模塊組織歧斟。文件或文件夾的名字是模塊名(module-name)纯丸,然后通過 mod module-name語句注冊和尋找模塊偏形。
新建一個 front_of_house.rs 文件用來表示 front_of_hourse 模塊,把 main.rs 里的內(nèi)容獨立出來觉鼻,在main里使用 pub mod front_of_house 聲明 front_of_hourse 模塊俊扭。

?  src git:(master) ? tree
.
├── front_of_house.rs
└── main.rs

0 directories, 2 files
?  src git:(master) ? cat front_of_house.rs main.rs
pub mod hosting {
    pub fn add_to_waitlist() {
        println!("add_to_waitlist");
    }

    pub fn seat_at_table() {
        println!("seat_at_table");
    }
}
pub mod serving {
    pub fn take_order(){
        println!("take_order");
    }

    pub fn serve_order(){
        println!("serve_order");
    }

    pub fn take_payment(){
        println!("take_payment");
    }
}

pub mod front_of_house; // 聲明模塊

fn main() {
    self::front_of_house::hosting::add_to_waitlist(); // 模塊的完整路徑
}

執(zhí)行 cargo run,可以正常的編譯運行坠陈。

0x01

下面把 front_of_house.rs 文件改成文件夾萨惑,并創(chuàng)建 hosting.rs 和 seving.rs 文件

pub fn add_to_waitlist() {
    println!("add_to_waitlist");
}

pub fn seat_at_table() {
    println!("seat_at_table");
}
pub fn take_order(){
    println!("take_order");
}

pub fn serve_order(){
    println!("serve_order");
}

pub fn take_payment(){
    println!("take_payment");
}
?  src git:(master) ? tree
.
├── front_of_house
│   ├── hosting.rs
│   └── serving.rs
└── main.rs

1 directory, 3 files

執(zhí)行 cargo run 會發(fā)現(xiàn)如下報錯:

?  front_of_house git:(master) ? cargo run
   Compiling demo v0.1.0 (/Users/master/rust/demo)
error[E0583]: file not found for module `front_of_house`
 --> src/main.rs:2:1
  |
2 | pub mod front_of_house;
  | ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: to create the module `front_of_house`, create file "src/front_of_house.rs" or "src/front_of_house/mod.rs"

error[E0433]: failed to resolve: could not find `hosting` in `front_of_house`
 --> src/main.rs:5:27
  |
5 |     self::front_of_house::hosting::add_to_waitlist();
  |                           ^^^^^^^ could not find `hosting` in `front_of_house`

報錯的地方是因為rust 無法找到 hosting 模塊。正如前文所說仇矾,文件或文件夾名是模塊名庸蔼,文件系統(tǒng)的組織可以是模塊的命名空間。但是 rust 搜索模塊使用的是 mod module-name 的方式注冊或搜索贮匕。
main.rs 通過 pub mod front_of_house; 語句找到了統(tǒng)計的文件夾front_of_house姐仅,但是 hosting 和 serving 模塊并沒注冊到 front_of_house 上,從報錯信息也可以看到。rust 建議我們在 front_of_house 文件夾內(nèi)創(chuàng)建一個mod.rs的文件掏膏。事實上劳翰,rust 會搜索文件夾下的是 mod.rs 文件,這個文件聲明了文件夾作為模塊的子模塊信息馒疹。
新建一個文件 mod.rs 佳簸,然后輸入下面內(nèi)容:

pub mod hosting;
pub mod serving;
?  src git:(master) ? vim front_of_house
?  src git:(master) ? tree
.
├── front_of_house
│   ├── hosting.rs
│   ├── mod.rs
│   └── serving.rs
└── main.rs

1 directory, 4 files

再次編譯就正常。

0x02

至此颖变,我們對rust的模塊組織有了更深的認(rèn)識生均。簡而言之就是,模塊的路徑可以是文件系統(tǒng)的路徑腥刹,不同于其他編程語言疯特,rust 需要顯示的注冊模塊。對于文件夾肛走,其內(nèi)部使用一個 mod.rs 的文件來注冊該文件內(nèi)的模塊漓雅。我們再修改一下上面的模塊組織,加深一下對模塊的理解

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
?  src git:(master) ? tree
.
├── front_of_house
│   ├── hosting
│   │   └── mod.rs
│   ├── mod.rs
│   └── serving.rs
└── main.rs

2 directories, 4 files

其中 front_of_house/hosting/mod.rs 的內(nèi)容是原 hosting.rs 的內(nèi)容朽色。當(dāng)模塊命名成文件的時候邻吞,需要其內(nèi)部的內(nèi)容都必須寫在 mod.rs 的文件里。

路徑訪問性

類似于在文件系統(tǒng)中使用路徑進(jìn)行導(dǎo)航的方式葫男,Rust 也使用路徑搜索模塊和其內(nèi)容抱冷。路徑有兩種形式:

  • 使用crate的名或字面量crate從根節(jié)點開始的絕對路徑
  • 使用self、super或內(nèi)部標(biāo)識符從當(dāng)前模塊開始的相對路徑

Rust中的所有條目(函數(shù)梢褐、方法旺遮、結(jié)構(gòu)體、枚舉盈咳、模塊及常量)默認(rèn)都是私有的耿眉。處于父級模塊中的條目無法使用子模塊中的私有條目,但子模塊中的條目可以使用它所有祖先模塊中的條目鱼响。
想要子模塊的內(nèi)容被外部應(yīng)用鸣剪,需要聲明為 pub 屬性。


上面例子的 front_of_house 模塊是隸屬于 bianry crate丈积。也可以組織到 lib crate 里筐骇。新建 lib.rs,并聲明 front_of_house 模塊

pub mod front_of_house;

修改 main.rs

use demo::front_of_house::hosting::add_to_waitlist;

fn main() {
    // demo::front_of_house::hosting::add_to_waitlist();
    add_to_waitlist()
}

文件目錄

?  src git:(master) ? tree
.
├── front_of_house
│   ├── hosting
│   │   └── mod.rs
│   ├── mod.rs
│   └── serving.rs
├── lib.rs
└── main.rs

2 directories, 5 files

總結(jié)


Rust 使用 Package Crate 和 Module 來組織項目代碼江滨。一個 Cargo 項目就是一個 Package铛纬,一個Package 可以有多個 Crate,Crate 是 Rust 代碼的最小編譯單元唬滑,也翻譯為單元包告唆。Crate 分為 Binary Crate 和 Lib Crate莫秆。
binary crate 可以編譯生成可執(zhí)行二進(jìn)制文件,lib crate 編譯用來共享的代碼模塊悔详。
每個Crate 可以有多個 Module镊屎,Module 是代碼接口命名空間的樹形組織。既可以組織成文件系統(tǒng)一樣的目錄樹結(jié)構(gòu)茄螃,也可以組織成獨立的文件缝驳。
最后,Rust 自身有很多新的概念归苍,這些內(nèi)容既和其他編程語言類似用狱,但又不能直接等效,Rust 創(chuàng)造了新名詞來描述這些概念拼弃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夏伊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吻氧,更是在濱河造成了極大的恐慌溺忧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盯孙,死亡現(xiàn)場離奇詭異鲁森,居然都是意外死亡,警方通過查閱死者的電腦和手機振惰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門歌溉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骑晶,你說我怎么就攤上這事痛垛。” “怎么了桶蛔?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵匙头,是天一觀的道長。 經(jīng)常有香客問我羽圃,道長乾胶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任朽寞,我火速辦了婚禮,結(jié)果婚禮上斩郎,老公的妹妹穿的比我還像新娘脑融。我一直安慰自己,他們只是感情好缩宜,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布肘迎。 她就那樣靜靜地躺著甥温,像睡著了一般。 火紅的嫁衣襯著肌膚如雪妓布。 梳的紋絲不亂的頭發(fā)上姻蚓,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音匣沼,去河邊找鬼狰挡。 笑死,一個胖子當(dāng)著我的面吹牛释涛,可吹牛的內(nèi)容都是我干的加叁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼唇撬,長吁一口氣:“原來是場噩夢啊……” “哼它匕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窖认,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤豫柬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扑浸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轮傍,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年首装,在試婚紗的時候發(fā)現(xiàn)自己被綠了创夜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡仙逻,死狀恐怖驰吓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情系奉,我是刑警寧澤檬贰,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站缺亮,受9級特大地震影響翁涤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萌踱,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一葵礼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧并鸵,春花似錦鸳粉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枯夜。三九已至,卻和暖如春艰山,著一層夾襖步出監(jiān)牢的瞬間湖雹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工曙搬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留摔吏,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓织鲸,卻偏偏與公主長得像舔腾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子搂擦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容