โครงสร้างโปรเจกต์ — Cargo.toml, src/, และระบบ Module
หมายเหตุ Playground: โครงสร้างโปรเจกต์เกี่ยวข้องกับหลายไฟล์และโครงสร้างไดเรกทอรีโดยเนื้อหา — ไม่สามารถสาธิตในไฟล์เดี่ยวของเบราว์เซอร์ได้ รันตัวอย่างในเครื่องด้วย
cargo newและcargo run
สิ่งที่ cargo new ให้คุณ
หัวข้อที่มีชื่อว่า “สิ่งที่ cargo new ให้คุณ”เมื่อคุณรัน 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)"]
สำหรับ Library (ไม่มี main แค่เป็น API สำหรับ Crate อื่นใช้):
cargo new --lib my-libflowchart TD root["my-lib/"] --> toml["Cargo.toml"] root --> src["src/"] src --> lib["lib.rs — library entry point (= index.ts that only exports)"]
Cargo.toml vs package.json
หัวข้อที่มีชื่อว่า “Cargo.toml vs package.json”// 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" }}# 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 ต่อเมื่อมีการร้องขอเท่านั้น
src/main.rs และ src/lib.rs
หัวข้อที่มีชื่อว่า “src/main.rs และ src/lib.rs”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 { ... }"] ใน TypeScript คุณใช้ import/export ใน Rust คุณใช้ mod เพื่อประกาศ Module และ use เพื่อนำ Items เข้า Scope:
// TypeScript ESM// src/utils.tsexport function add(a: number, b: number): number { return a + b;}
// src/main.tsimport { add } from './utils';console.log(add(1, 2));// src/utils.rspub fn add(a: i32, b: i32) -> i32 { a + b}
// src/main.rsmod utils; // declares the module (looks for src/utils.rs)use utils::add;
fn main() { println!("{}", add(1, 2));}ไดเรกทอรี target/
หัวข้อที่มีชื่อว่า “ไดเรกทอรี target/”เมื่อรัน 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"]
เพิ่ม target/ ลงใน .gitignore ได้เลย ซึ่ง Cargo ใส่ให้อัตโนมัติอยู่แล้วเมื่อคุณรัน cargo new
Crates vs node_modules
หัวข้อที่มีชื่อว่า “Crates vs node_modules”ใน 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 ไปแล้ว)
Cargo.lock
หัวข้อที่มีชื่อว่า “Cargo.lock”เหมือน 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