ข้ามไปยังเนื้อหา

โครงสร้างโปรเจกต์ — Cargo.toml, src/, และระบบ Module

หมายเหตุ Playground: โครงสร้างโปรเจกต์เกี่ยวข้องกับหลายไฟล์และโครงสร้างไดเรกทอรีโดยเนื้อหา — ไม่สามารถสาธิตในไฟล์เดี่ยวของเบราว์เซอร์ได้ รันตัวอย่างในเครื่องด้วย cargo new และ cargo run

เมื่อคุณรัน cargo new my-app Cargo จะสร้างโปรเจกต์ที่เล็กแต่ครบถ้วน:

flowchart TD
  root["my-app/"] --> toml["Cargo.toml — project manifest (= package.json)"]
  root --> lock["Cargo.lock — pinned dependency versions (= package-lock.json)"]
  root --> src["src/"]
  src --> main["main.rs — entry point (= src/index.ts)"]
What cargo new gives you (binary crate)

สำหรับ Library (ไม่มี main แค่เป็น API สำหรับ Crate อื่นใช้):

Terminal window
cargo new --lib my-lib
flowchart TD
  root["my-lib/"] --> toml["Cargo.toml"]
  root --> src["src/"]
  src --> lib["lib.rs — library entry point (= index.ts that only exports)"]
Library crate layout
TypeScript
// package.json
{
"name": "my-app",
"version": "1.0.0",
"description": "A Node.js app",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
},
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/express": "^4.17.0"
}
}
Rust
# Cargo.toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2021" # Rust edition (like target in tsconfig)
# No separate devDependencies:
# [dependencies] = runtime deps
# [dev-dependencies] = test-only deps
[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
[dev-dependencies]
pretty_assertions = "1"

ความแตกต่างหลัก:

  • ไม่มี Section scripts คุณรัน cargo run, cargo test ฯลฯ โดยตรง
  • edition สอดคล้องกับ Rust language edition (2015, 2018, 2021) ใช้ 2021 เสมอสำหรับโปรเจกต์ใหม่
  • Dependencies ไม่ต้องมี Package @types/ Rust types เป็นส่วนหนึ่งของ Crate เสมอ
  • Feature flags (features = ["derive"]) คือของเทียบเท่า Optional peer dependency หรือ Configuration flag ในฝั่ง Rust ช่วยให้ Crate เปิด API เพิ่มเติมที่ Compile ต่อเมื่อมีการร้องขอเท่านั้น

Binary crate มี src/main.rs ส่วน Library crate มี src/lib.rs และจะมีทั้งคู่ในโปรเจกต์เดียวกันก็ได้ — เก็บ Logic ที่แชร์ไว้ใน src/lib.rs แล้วให้ src/main.rs เรียกใช้

flowchart TD
  root["my-app/"] --> src["src/"]
  src --> main["main.rs — fn main() { ... }"]
  src --> lib["lib.rs — pub fn library_code() { ... }"]
  src --> utils["utils.rs — a module (pub mod utils;)"]
  src --> models["models/"]
  models --> mod["mod.rs — module root (or models.rs in Rust 2018+)"]
  models --> user["user.rs — pub struct User { ... }"]
A project with modules

ใน TypeScript คุณใช้ import/export ใน Rust คุณใช้ mod เพื่อประกาศ Module และ use เพื่อนำ Items เข้า Scope:

TypeScript
// TypeScript ESM
// src/utils.ts
export function add(a: number, b: number): number {
return a + b;
}
// src/main.ts
import { add } from './utils';
console.log(add(1, 2));
Rust
// src/utils.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// src/main.rs
mod utils; // declares the module (looks for src/utils.rs)
use utils::add;
fn main() {
println!("{}", add(1, 2));
}

เมื่อรัน cargo build Rust จะ Compile ทุกอย่างลงใน target/ เทียบได้กับ dist/ บวก node_modules/.cache/ และไม่ควร Commit เข้า Version control

flowchart TD
  root["target/"] --> debug["debug/ — cargo build (fast compile, no optimisation)"]
  debug --> dbin["my-app — the executable"]
  root --> release["release/ — cargo build --release (slower compile, fast binary)"]
  release --> rbin["my-app"]
The target/ directory

เพิ่ม target/ ลงใน .gitignore ได้เลย ซึ่ง Cargo ใส่ให้อัตโนมัติอยู่แล้วเมื่อคุณรัน cargo new

ใน JavaScript npm install ดาวน์โหลด Packages ลงใน node_modules/ ภายในโปรเจกต์ของคุณ ใน Rust cargo add <crate> ดาวน์โหลด Packages (เรียกว่า Crates) ลงใน Global registry cache ที่ ~/.cargo/registry/ ไดเรกทอรี target/ ของโปรเจกต์มี Compiled artifacts แต่ Source แชร์กันในทุกโปรเจกต์บนเครื่องของคุณ

Global cache หมายความว่า:

  • ไม่มีการ Duplicate Crate เดิมต่อโปรเจกต์
  • cargo clean ลบ target/ แต่เก็บ Download cache ไว้
  • การ Build Crate เดิม Version เดิมสองครั้งนั้นเกือบจะทันที (Compile ไปแล้ว)

เหมือน package-lock.json Cargo.lock จะ Pin Version ที่แน่นอนของทุก Transitive dependency สำหรับโปรเจกต์ Binary ให้ Commit Cargo.lock สำหรับ Libraries ที่ Publish ไปยัง crates.io ให้เพิ่มลงใน .gitignore — เหมือนกับที่คุณไม่ Commit package-lock.json ใน Published npm package

อะไรคือ Rust เทียบเท่ากับ package.json?
Rust เก็บ Compiled build artifacts ไว้ที่ไหน?
`mod utils;` ใน Rust ทำอะไร?
สำหรับ Rust library crate ที่ Publish แล้ว ควร Commit Cargo.lock หรือไม่?