- Rust ช่วยให้มั่นใจถึงความปลอดภัยของหน่วยความจำในระหว่างการคอมไพล์ผ่านการเป็นเจ้าของ การยืม และอายุการใช้งาน โดยไม่ใช้การรวบรวมขยะ
- ระบบประเภทและกฎการสร้างนามแฝงอนุญาตให้มีการทำงานพร้อมกันโดยไม่ต้องแข่งขันข้อมูลโดยใช้มิวเท็กซ์ ช่องสัญญาณ และตัวชี้อัจฉริยะ
- Cargo, crates.io และระบบนิเวศที่แอ็คทีฟทำให้การจัดการการอ้างอิง การรวบรวม การทดสอบ และการปรับใช้เป็นเรื่องง่ายยิ่งขึ้น
- การทำความเข้าใจโครงสร้าง ค่า enum ตัวเลือก และผลลัพธ์ถือเป็นกุญแจสำคัญในการจัดการข้อผิดพลาดและการสร้างแบบจำลองข้อมูลที่ปลอดภัยในแอปพลิเคชันพร้อมกัน
Rust ได้กลายเป็นหนึ่งในภาษาเหล่านั้น นักพัฒนาระบบทุกคนต้องได้ยินเรื่องนี้ซ้ำแล้วซ้ำเล่ามันเร็วพอๆ กับ C และ C++ แต่กลับให้ความสำคัญกับความปลอดภัยของหน่วยความจำและการทำงานพร้อมกันได้อย่างดีเยี่ยม นี่ไม่ใช่แค่การตลาดแบบลอยๆ: การออกแบบของมันหมุนรอบการที่คอมไพเลอร์ตรวจจับข้อผิดพลาดระหว่างการคอมไพล์ ซึ่งเป็นข้อผิดพลาดที่ในภาษาอื่นๆ คุณจะเห็นก็ต่อเมื่อระบบกำลังอยู่ในระหว่างการผลิต... หรือเมื่อระบบเกิดขัดข้อง
หากคุณสนใจที่จะเข้าใจ Rust ช่วยให้หน่วยความจำปลอดภัยโดยไม่ต้องเก็บขยะและทำงานพร้อมกันโดยไม่ต้องกลัวการรันข้อมูลได้อย่างไรบทช่วยสอนนี้เหมาะสำหรับคุณ เราจะครอบคลุมทุกอย่างตั้งแต่พื้นฐานของภาษาและระบบนิเวศของมัน ไปจนถึงแนวคิดสำคัญๆ เช่น การเป็นเจ้าของ การยืม ประเภทข้อมูลแบบผสม เครื่องมืออย่าง Cargo และแม้แต่ดูประเภทข้อมูลแบบอะตอมมิกและการล็อกจากมุมมองที่เข้าถึงได้ง่ายขึ้นสำหรับผู้ที่เพิ่งเริ่มใช้ระบบการทำงานพร้อมกัน โดยทั้งหมดนี้มุ่งเน้นไปที่ความปลอดภัยและประสิทธิภาพ
บทช่วยสอน Rust: ประสิทธิภาพ ความปลอดภัยของหน่วยความจำ และการทำงานพร้อมกัน
Rust เป็นภาษาการเขียนโปรแกรม การเขียนโปรแกรม วัตถุประสงค์ทั่วไปและหลายกระบวนทัศน์ ออกแบบมาสำหรับ การเขียนโปรแกรมระบบระดับต่ำรวมถึงโครงการระดับสูงจาก OSจากเอ็นจิ้นเกมและเบราว์เซอร์ไปจนถึงบริการเว็บประสิทธิภาพสูง มีต้นกำเนิดมาจาก Mozilla โดยมีเป้าหมายเพื่อปรับปรุงความปลอดภัยของซอฟต์แวร์ โดยเฉพาะในส่วนประกอบที่ละเอียดอ่อน เช่น เอ็นจิ้นเบราว์เซอร์
ลักษณะเด่นของมันคือ รับประกันความปลอดภัยของหน่วยความจำในเวลาคอมไพล์ โดยไม่ต้องใช้ตัวรวบรวมขยะ แต่ Rust จะใช้ระบบความเป็นเจ้าของและตัวตรวจสอบการยืมที่ติดตามอายุการใช้งานของแต่ละค่าและการอ้างอิง วิธีนี้ช่วยหลีกเลี่ยงปัญหาทั่วไป เช่น ตัวชี้ที่ค้าง บัฟเฟอร์ล้น หรือหน่วยความจำรั่วไหล โดยไม่ต้องใช้การนับการอ้างอิงหรือการรวบรวมขยะอัตโนมัติ
นอกจากนี้ Rust ยังได้รับการออกแบบมาให้ใช้งานง่ายยิ่งขึ้น การทำงานพร้อมกันอย่างปลอดภัยรูปแบบประเภทและความเป็นเจ้าของช่วยป้องกันการแข่งขันข้อมูลระหว่างเธรด อย่างน้อยก็ในขณะที่ยังคงอยู่ในโค้ด Rust ที่ปลอดภัย ซึ่งหมายความว่าสามารถตรวจพบสถานการณ์อันตรายหลายอย่างได้ในระหว่างการคอมไพล์ ก่อนที่จะมีการประมวลผลแม้แต่บรรทัดเดียว
ด้วยเหตุผลทั้งหมดนี้ บริษัทใหญ่ๆ จึงชอบ Dropbox, Microsoft, Amazon หรือ Google พวกเขาได้นำ Rust มาใช้ในส่วนสำคัญของโครงสร้างพื้นฐาน และไม่ใช่เรื่องบังเอิญที่ Rust ติดอันดับหนึ่งในผลสำรวจของ Stack Overflow ในฐานะหนึ่งในภาษาที่นักพัฒนาชื่นชอบมากที่สุดมาหลายปี Rust ผสานประสิทธิภาพแบบ C++ เข้ากับชุดเครื่องมือที่ทันสมัย (Cargo, crates.io) และชุมชนที่กระตือรือร้นที่เรียกว่า Rustaceans
แนวคิดพื้นฐาน: ภาษาการเขียนโปรแกรม ประเภท และหน่วยความจำ
ก่อนที่จะเจาะลึกถึงรายละเอียดเฉพาะของความปลอดภัยของหน่วยความจำและการทำงานพร้อมกัน ควรชี้แจงแนวคิดทั่วไปบางประการที่ปรากฏตลอด เวลา เมื่อทำงานกับ Rust โดยเฉพาะอย่างยิ่งหากคุณมาจากภาษาอื่นหรือเพิ่งเริ่มเขียนโปรแกรม.
ภาษาการเขียนโปรแกรมนั้นโดยที่สุดแล้วก็คือ ชุดกฎและโครงสร้างที่ช่วยให้คุณอธิบายอัลกอริทึมได้ และแปลงเป็นโปรแกรมที่สามารถทำงานได้ Rust คอมไพล์เป็นโค้ดเครื่องเนทีฟโดยใช้คอมไพเลอร์ rustcดังนั้นประสิทธิภาพที่คุณได้รับมักจะเท่าเทียมกับ C และ C++
การจัดการหน่วยความจำเป็นกระบวนการที่โปรแกรม สำรองและปล่อยบล็อกหน่วยความจำในขณะที่กำลังทำงานข้อผิดพลาดในส่วนนี้มักร้ายแรง เช่น การรั่วไหลของหน่วยความจำ (ไม่สามารถปล่อยหน่วยความจำที่ไม่ได้ใช้), ความเสียหายของข้อมูลจากการเขียนข้อมูลนอกขอบเขต หรือการใช้หน่วยความจำหลังจากปล่อยหน่วยความจำแล้ว Rust แก้ไขปัญหานี้ด้วยระบบประเภทข้อมูลที่แข็งแกร่งและกฎเกณฑ์อย่างเป็นทางการสำหรับการเป็นเจ้าของ การยืม และอายุการใช้งาน
Rust ยังมีคำศัพท์เช่น ประเภทและตัวชี้ที่ชาญฉลาดประเภท (Type) อธิบายถึงชนิดของข้อมูลที่ตัวแปรจัดเก็บ (จำนวนเต็ม, จำนวนทศนิยม, สตริง, โครงสร้าง ฯลฯ) และวิธีจัดการข้อมูลเหล่านั้น ตัวชี้อัจฉริยะ (ตัวอย่างเช่น Box, Rc y Arc) เป็นโครงสร้างที่ห่อหุ้มที่อยู่หน่วยความจำและเพิ่มตรรกะพิเศษเพื่อจัดการทรัพยากรอย่างปลอดภัย เช่น การนับการอ้างอิงที่แชร์หรือการย้ายค่าไปยังฮีป
ในด้านการแข่งขัน แนวคิดเช่น เงื่อนไขการแข่งขัน มิวเท็กซ์ และช่องทาง สิ่งเหล่านี้กลายเป็นสิ่งที่ขาดไม่ได้: สภาวะการแข่งขันเกิดขึ้นเมื่อเธรดหลายเธรดเข้าถึงและแก้ไขทรัพยากรที่ใช้ร่วมกันพร้อมๆ กันโดยไม่มีการประสานงานที่เหมาะสม มิวเท็กซ์ (การแยกกันซึ่งกันและกัน) รับรองว่ามีเพียงเธรดเดียวเท่านั้นที่เข้าสู่ส่วนที่สำคัญในแต่ละครั้ง และช่องทางอนุญาตให้ส่งข้อความระหว่างเธรดโดยไม่ต้องแชร์หน่วยความจำโดยตรง
เหตุใดจึงควรเรียนรู้ Rust: ความปลอดภัยของหน่วยความจำและการทำงานพร้อมกันอย่างไม่หวั่นเกรง
Rust ได้รับชื่อเสียงเพราะว่ามันนำเสนอ เสาหลักอันทรงคุณค่าสามประการสำหรับการเขียนโปรแกรมสมัยใหม่ประสิทธิภาพ ความปลอดภัย และเครื่องมือปัจจุบัน มาดูกันว่าทำไมประเด็นเหล่านี้จึงมีความสำคัญ
ในส่วนของประสิทธิภาพ Rust คอมไพล์โดยตรงไปยังไบนารีดั้งเดิม โดยไม่ต้องใช้เครื่องเสมือนหรืออินเทอร์พรีเตอร์ โมเดลการแยกส่วนแบบต้นทุนเป็นศูนย์มีจุดมุ่งหมายเพื่อให้แน่ใจว่าการแยกส่วนระดับสูงจะไม่เพิ่มภาระงานในขณะรันไทม์ ดังนั้นจึงเหมาะอย่างยิ่งสำหรับการพัฒนาระบบ เกมส่วนประกอบของเบราว์เซอร์หรือไมโครเซอร์วิสที่มีความหน่วงต่ำ
ความปลอดภัยของหน่วยความจำนั้นขึ้นอยู่กับ ระบบการเป็นเจ้าของและการกู้ยืมไม่มีตัวรวบรวมขยะ แต่คอมไพเลอร์รู้แน่ชัดว่าใครเป็นเจ้าของทรัพยากรแต่ละรายการ เมื่อใดที่ทรัพยากรนั้นไม่จำเป็นอีกต่อไป และสามารถปล่อยทรัพยากรนั้นได้เมื่อใด วิธีนี้ช่วยป้องกันการรั่วไหล ตัวชี้ที่ค้างอยู่ และข้อผิดพลาดมากมายที่ทำให้การเขียนโปรแกรม C และ C++ เป็นอันตรายมาโดยตลอด
ในด้านการแข่งขัน รัสต์ไล่ตามสิ่งที่มักเรียกกันว่า “การทำงานพร้อมกันโดยปราศจากความกลัว”ระบบประเภทข้อมูลจะป้องกันไม่ให้มีรากข้อมูลอยู่ในโค้ดที่ปลอดภัย หากคุณต้องการแบ่งปันข้อมูลที่เปลี่ยนแปลงได้ระหว่างเธรด คุณจะต้องใช้ไพรมิทีฟที่เหมาะสม เช่น Mutex, RwLock o Arcและคอมไพเลอร์จะตรวจสอบให้แน่ใจว่ากฎการสร้างนามแฝงและการเปลี่ยนแปลงได้รับการเคารพ
ประสบการณ์การพัฒนาได้รับการปรับปรุงด้วยเครื่องมือที่ทันสมัย เช่น สินค้ามาพร้อมกับตัวจัดการแพ็กเกจและโครงสร้างพื้นฐานสำหรับการสร้างแบบบูรณาการ และระบบนิเวศไลบรารีที่กว้างขวาง (crates) ครอบคลุมทุกอย่างตั้งแต่เครือข่ายแบบอะซิงโครนัส (Tokyo) ไปจนถึงเฟรมเวิร์กเว็บ (Actix, Rocket, Axum) ทั้งหมดนี้ได้รับการสนับสนุนจากชุมชนที่เปิดกว้าง เปี่ยมด้วยประสิทธิภาพ และอดทน โดยเฉพาะอย่างยิ่งสำหรับผู้เริ่มต้น
การติดตั้งและเครื่องมือที่จำเป็น: rustup, rustc และ Cargo
ในการเขียนและรันโปรแกรมแรกของคุณใน Rust วิธีปกติในการเริ่มต้นคือการติดตั้งชุดเครื่องมืออย่างเป็นทางการโดยใช้ สนิม (ดู การแนะนำ Rust แบบสมบูรณ์), โปรแกรมติดตั้งและจัดการเวอร์ชันที่ใช้งานง่ายซึ่งทำงานบนระบบปฏิบัติการหลักทั้งหมด
กับ สนิม คุณสามารถติดตั้ง อัปเดต และสลับระหว่าง Rust เวอร์ชันต่างๆ (stable, beta, nightly) ได้โดยไม่ทำให้ระบบเสียหาย เพียงไปที่หน้าเครื่องมือ Rust อย่างเป็นทางการ แล้วทำตามขั้นตอนสำหรับระบบของคุณ เมื่อติดตั้งแล้ว คอมไพเลอร์ก็จะพร้อมใช้งาน rustc, ผู้จัดการโครงการ cargo และของเขาเอง rustup ในของคุณ สถานีปลายทาง.
คอมไพเลอร์ rustc มันคือสิ่งที่แปลงซอร์สโค้ดของคุณให้เป็นไฟล์ไบนารีหรือไลบรารีที่ปฏิบัติการได้ แม้ว่าคุณจะสามารถเรียกใช้งานมันได้โดยตรงด้วย คำสั่ง ในขณะที่ rustc main.rsในทางปฏิบัติ คุณแทบจะทำงานผ่าน Cargo เสมอ ซึ่งจัดการการโทร rustc ด้วยตัวเลือกที่เหมาะสม
เครื่องมือหลักของเวิร์กโฟลว์คือ สินค้าด้วยคำสั่งเพียงไม่กี่คำ คุณก็สามารถสร้างโปรเจ็กต์ใหม่ จัดการ dependencies คอมไพล์ รัน ทดสอบ และเผยแพร่แพ็กเกจบน crates.io ได้ คำสั่งพื้นฐานที่ใช้กันทั่วไป ได้แก่: cargo new, cargo build, cargo run, cargo test y cargo checkซึ่งตรวจสอบโค้ดโดยไม่สร้างไฟล์ปฏิบัติการสุดท้าย เหมาะสำหรับการตรวจจับข้อผิดพลาดอย่างรวดเร็ว
หากคุณต้องการปรับแต่งโดยไม่ต้องติดตั้งอะไรเลย สนามเด็กเล่นสนิม (ตัวดำเนินการออนไลน์อย่างเป็นทางการ) และแพลตฟอร์มเช่น Replit ช่วยให้คุณเขียนและรันโค้ดชิ้นเล็กๆ จากเบราว์เซอร์ได้ เหมาะอย่างยิ่งสำหรับการทดลองกับตัวอย่างหน่วยความจำและการทำงานพร้อมกันโดยไม่ต้องตั้งค่าสภาพแวดล้อมทั้งหมด
โปรแกรมแรกของคุณ: สวัสดี Rust และโฟลว์พื้นฐาน
วิธีคลาสสิกในการเริ่มการสนทนาในภาษาใดก็ตามคือการใช้ "สวัสดีโลก" อันโด่งดัง ใน Rust ไฟล์ main.rs ขั้นต่ำอาจมีบางอย่างที่เรียบง่าย เช่น ฟังก์ชัน main ที่พิมพ์สตริงบนหน้าจอ.
คำสำคัญ fn บ่งบอกว่าเรากำลังกำหนดฟังก์ชันและ main นี่คือจุดเข้าใช้งานของโปรแกรม บล็อกโค้ดของฟังก์ชันจะอยู่ภายในวงเล็บปีกกา หากต้องการเขียนไปยังคอนโซล ให้ใช้ แมโคร println!ซึ่งยอมรับสตริงตัวอักษร (หรือเทมเพลตที่มีบุ๊กมาร์ก) และส่งไปยังเอาท์พุตมาตรฐานที่ลงท้ายด้วยอักขระขึ้นบรรทัดใหม่
หากคุณคอมไพล์โดยตรงกับ rustc main.rsคุณจะได้รับไฟล์ไบนารีที่สามารถปฏิบัติการได้ (ตัวอย่างเช่น main o main.exe (ขึ้นอยู่กับระบบ) เมื่อรันแล้ว คุณจะเห็นข้อความในเทอร์มินัล แต่วิธีการใช้งาน Rust แบบง่ายๆ คือให้ Cargo เป็นผู้นำในโครงการ
กับ cargo new nombre_proyecto โครงสร้างโฟลเดอร์จะถูกสร้างขึ้นโดยอัตโนมัติด้วย src/main.rs เตรียมไว้แล้วด้วย "สวัสดีโลก" และไฟล์ Cargo.toml ซึ่งประกอบด้วยข้อมูลเมตาและการอ้างอิงในอนาคต จากนั้น cargo run คอมไพล์และรันไบนารีและจะคอมไพล์ใหม่เมื่อตรวจพบการเปลี่ยนแปลงเท่านั้น
วิธีการทำงานนี้ไม่เพียงแต่สะดวกเท่านั้น แต่ยังทำให้คุณคุ้นเคยกับการใช้ระบบนิเวศ Rust มาตรฐานตั้งแต่เริ่มต้น ซึ่งมีประโยชน์มากเมื่อคุณเริ่มเพิ่มกล่องสำหรับการทำงานพร้อมกัน เครือข่าย การทดสอบ หรืออะไรก็ตามที่คุณต้องการ
// เราประกาศฟังก์ชัน main: จุดเข้าโปรแกรม fn main() { // เราใช้แมโคร println! เพื่อพิมพ์ข้อความไปยังคอนโซล println!("Hello, world!"); }
ตัวแปร การเปลี่ยนแปลง และชนิดข้อมูลพื้นฐาน
ใน Rust ตัวแปรจะถูกประกาศด้วยคำสำคัญ letและตามค่าเริ่มต้น ไม่เปลี่ยนแปลงกล่าวอีกนัยหนึ่ง เมื่อคุณกำหนดค่าให้แล้ว คุณจะไม่สามารถแก้ไขได้ เว้นแต่คุณจะประกาศให้ชัดเจนว่าสามารถเปลี่ยนแปลงได้ด้วย mut.
โดยค่าเริ่มต้นแล้ว ความไม่เปลี่ยนแปลงจะช่วยหลีกเลี่ยงข้อผิดพลาดทางตรรกะที่ละเอียดอ่อน โดยเฉพาะอย่างยิ่งในโปรแกรมที่ทำงานพร้อมกัน ซึ่งหลายเธรดอาจต้องการเปลี่ยนแปลงค่าเดียวกัน หากคุณต้องการเปลี่ยนแปลง ให้เขียนคำสั่งดังนี้ let mut contador = 0;จากนั้นคุณสามารถกำหนดค่าใหม่ได้ contador.
สนิมยังช่วยให้สิ่งที่เรียกว่า แชโดว์คุณสามารถประกาศตัวแปรใหม่ที่มีชื่อเดียวกันภายในขอบเขตเดียวกัน โดยซ่อนตัวแปรเดิมไว้ได้ วิธีนี้ไม่เหมือนกับการ mutating เพราะคุณกำลังสร้างค่าใหม่ (ซึ่งอาจเป็นชนิดอื่นก็ได้) ตัวอย่างเช่น คุณสามารถแปลงจากสตริงเป็นจำนวนเต็มโดยใช้ชื่อเดียวกันได้ ตราบใดที่เป็นการประกาศใหม่ที่มี let.
ระบบประเภทของ Rust เป็นแบบคงที่ ซึ่งหมายความว่า ชนิดของตัวแปรแต่ละตัวจะทราบได้เมื่อทำการคอมไพล์อย่างไรก็ตาม การอนุมานประเภทนั้นค่อนข้างทรงพลัง: หากคุณเขียน let x = 5;คอมไพเลอร์ถือว่ามันเป็น i32 เว้นแต่คุณจะแจ้งเป็นอย่างอื่น คุณสามารถเพิ่มหมายเหตุได้ เช่น let x: i64 = 5; เมื่อคุณต้องการที่จะชัดเจน
ประเภทสเกลาร์ที่มีให้เลือก ได้แก่ จำนวนเต็มที่มีเครื่องหมายและไม่มีเครื่องหมาย (i8, u8, i32, ฯลฯ) อันลอยน้ำ (f32, f64), บูลีน (bool) และอักขระ Unicode (char). ประเภทที่เรียบง่ายเหล่านี้มักจะคัดลอกได้ในราคาถูกและหลาย ๆ ประเภทก็ใช้คุณลักษณะนี้ Copyซึ่งหมายความว่าเมื่อคุณกำหนดหรือส่งต่อให้กับฟังก์ชัน ข้อมูลเหล่านั้นจะถูกคัดลอกแทนที่จะย้าย
สตริงใน Rust: &str และ String
การจัดการข้อความใน Rust อาจจะสับสนเล็กน้อยในตอนแรกเนื่องจากสามารถแยกความแตกต่างระหว่าง “ชิ้นส่วน” ของโซ่และโซ่ที่เป็นกรรมสิทธิ์สองชิ้นสำคัญคือ &str y String.
Un &str เป็น ชิ้นส่วนของโซ่ที่ไม่เปลี่ยนแปลงมุมมองของลำดับไบต์ UTF-8 ที่เก็บไว้ที่ไหนสักแห่ง ตัวอย่างทั่วไปได้แก่ตัวอักษร เช่น "Hola"ซึ่งเป็นประเภท &'static str (พวกมันมีอยู่ตลอดช่วงชีวิตของโปรแกรมและฝังอยู่ในไบนารี) สไลซ์ไม่ได้เป็นเจ้าของข้อมูล แต่เพียงชี้ไปที่ข้อมูลเท่านั้น
Stringในทางกลับกันเป็น สตริงของตัวเอง เปลี่ยนแปลงได้ และโฮสต์อยู่ในฮีปสามารถปรับขนาด เชื่อมโยง ส่งผ่านระหว่างฟังก์ชันต่างๆ โดยการย้ายคุณสมบัติ ฯลฯ ได้ มักใช้เมื่อคุณต้องการสร้างข้อความแบบไดนามิกหรือจัดเก็บในระยะยาวภายในโครงสร้าง
ในหลายสถานการณ์คุณจะเปลี่ยนแปลงระหว่างสิ่งหนึ่งกับอีกสิ่งหนึ่ง ตัวอย่างเช่น คุณจะสร้าง String::from("hola") จากชิ้นหนึ่งหรือคุณจะยืม &str หนึ่ง String โดยการส่งการอ้างอิงไปยังฟังก์ชันที่จำเป็นต้องอ่านเท่านั้น
การแยกข้อมูลที่เป็นของเจ้าของและข้อมูลที่ถูกยืมมานั้นถือเป็นกุญแจสำคัญในการจัดการหน่วยความจำ และขยายไปยังส่วนอื่นๆ ของภาษาด้วย คอลเลกชัน โครงสร้าง และค่าแจงนับจะปฏิบัติตามแนวคิดเดียวกันว่าใครเป็นเจ้าของและใครดูเท่านั้น
ฟังก์ชั่น การควบคุมการไหล และความคิดเห็น
ฟังก์ชันใน Rust ถูกกำหนดด้วย fn และอนุญาตให้โปรแกรมถูกจัดเป็นหน่วยตรรกะที่นำกลับมาใช้ใหม่ได้ แต่ละฟังก์ชันจะระบุ ประเภทของพารามิเตอร์และประเภทการส่งคืน ตามลูกศร ->หากไม่ส่งคืนสิ่งใดที่มีความหมาย จะถือว่าเป็นประเภทเอกภาพ ().
รายละเอียดที่สำคัญคือนิพจน์สุดท้ายในฟังก์ชัน (หรือบล็อกใดๆ) ที่ไม่มีเครื่องหมายอัฒภาคจะถูกนำมาเป็นค่าส่งคืนโดยนัย คุณสามารถใช้ return สำหรับการคืนสินค้าล่วงหน้าแต่ในรหัสสำนวน คุณมักจะละเว้นนิพจน์สุดท้ายไป ;.
การควบคุมการไหลได้รับการจัดการด้วยคลาสสิก if/elseลูป loop, while y forใน Rust, if เป็นนิพจน์ที่คืนค่าเพื่อให้คุณสามารถใช้งานได้โดยตรง letโดยให้สาขาส่งคืนชนิดเดียวกัน ลูป for โดยทั่วไปแล้วจะมีการวนซ้ำตามช่วงหรือตัววนซ้ำของคอลเลกชัน และเป็นตัวเลือกที่แนะนำแทนดัชนีแบบกำหนดเอง
เพื่อบันทึกรหัสและทำให้ชีวิตง่ายขึ้นสำหรับใครก็ตามที่มาหลังจากนี้ (รวมถึงตัวคุณเองในอีกหนึ่งเดือน) คุณสามารถใช้ แสดงความคิดเห็นด้วย // หรือบล็อคด้วย /* ... */นอกจากนี้ Rust ยังเสนอความคิดเห็นเกี่ยวกับเอกสารด้วย /// ซึ่งจะกลายเป็นเอกสารที่สร้างขึ้น แม้ว่าจะเหมาะกับโครงการขนาดใหญ่มากกว่าก็ตาม
ความเป็นเจ้าของ การให้ยืม และอายุการใช้งาน: รากฐานของความมั่นคงของความทรงจำ
เรามาถึงจุดสำคัญของโมเดลหน่วยความจำของ Rust: ระบบของ การเป็นเจ้าของ การกู้ยืม และอายุการใช้งานกฎเหล่านี้ช่วยให้แน่ใจว่าการอ้างอิงนั้นถูกต้องเสมอและหน่วยความจำจะถูกปล่อยอย่างปลอดภัยโดยไม่มีขยะสะสม
กฎพื้นฐานของการเป็นเจ้าของนั้นระบุได้ง่าย แม้ว่าในตอนแรกอาจเข้าใจได้ยากก็ตาม: แต่ละค่าจะมีเจ้าของเพียงรายเดียวในแต่ละคราวจะมีเจ้าของได้เพียงคนเดียวเท่านั้น และเมื่อเจ้าของออกจากขอบเขต ค่าจะถูกทำลายและหน่วยความจำจะถูกปล่อยออกไป ยกตัวอย่างเช่น สิ่งนี้ใช้ได้กับ String: เมื่อบล็อกที่ประกาศไว้เสร็จสมบูรณ์แล้ว จะมีการเรียกใช้งานโดยอัตโนมัติ drop ซึ่งจะช่วยเพิ่มหน่วยความจำฮีป
เมื่อคุณกำหนดค่าที่เหมาะสมให้กับตัวแปรอื่นหรือส่งค่าไปยังฟังก์ชัน คุณสมบัติจะถูกย้าย ซึ่งหมายความว่า ตัวแปรดั้งเดิมจะสิ้นสุดความถูกต้องหลังจากการย้ายความหมายของการเคลื่อนไหวนี้หลีกเลี่ยงการปล่อยซ้ำสองครั้ง เนื่องจากไม่มีเจ้าของสองคนพยายามที่จะปล่อยทรัพยากรเดียวกัน
เพื่อให้หลายส่วนของโปรแกรมสามารถเข้าถึงค่าเดียวกันได้โดยไม่ต้องเปลี่ยนความเป็นเจ้าของ Rust จึงได้เพิ่มการอ้างอิงและการยืม เมื่อคุณยืม คุณจะสร้างการอ้างอิง &T (ไม่เปลี่ยนแปลง) หรือ &mut T (เปลี่ยนแปลงได้) ให้เป็นมูลค่าโดยไม่ต้องโอนกรรมสิทธิ์ การกู้ยืมเงินนั้นมีข้อจำกัดตามกฎของผู้ตรวจสอบการกู้ยืมซึ่งตรวจสอบว่าข้อมูลอ้างอิงจะไม่คงอยู่เกินข้อมูลที่ชี้ไป และการเข้าถึงแบบเปลี่ยนแปลงได้และแบบแชร์ไม่ได้ปะปนกันจนเป็นอันตราย
กฎเกณฑ์ของการกู้ยืมสามารถสรุปได้ดังนี้: ในเวลาใดก็ตาม คุณสามารถมีได้ การอ้างอิงที่ไม่เปลี่ยนแปลงหลายรายการ เป็นค่าหรือ การอ้างอิงแบบเปลี่ยนแปลงได้เพียงครั้งเดียวแต่ไม่ใช่ทั้งสองอย่างในเวลาเดียวกัน วิธีนี้จะช่วยขจัดปัญหาการแข่งขันในหน่วยความจำที่ใช้ร่วมกัน ซึ่งอาจเกิดจากผู้อ่านหลายคน หรือมีผู้เขียนแยกกัน ไม่ควรมีผู้อ่านและผู้เขียนพร้อมกันในข้อมูลเดียวกันในเวลาเดียวกัน
ประเภทคอมโพสิต: โครงสร้าง, อีนัม และตัวชี้อัจฉริยะ
Rust มีวิธีต่างๆ มากมายในการจัดกลุ่มข้อมูลที่เกี่ยวข้องให้เป็นโครงสร้างที่สมบูรณ์ยิ่งขึ้น โดยเริ่มจาก โครงสร้างโครงสร้างช่วยให้คุณสามารถกำหนดประเภทแบบกำหนดเองด้วยฟิลด์ที่มีชื่อ เช่น ผู้ใช้พร้อมอีเมล ชื่อ สถานะกิจกรรม และตัวนับการเข้าสู่ระบบ
ในการสร้างอินสแตนซ์ของโครงสร้าง คุณต้องกรอกข้อมูลในฟิลด์ทั้งหมด และสามารถทำเครื่องหมายตัวแปรที่มีโครงสร้างนั้นว่าสามารถเปลี่ยนแปลงได้เพื่อแก้ไขค่าในภายหลัง นอกจากนี้ยังมีไวยากรณ์ struct update ซึ่งช่วยให้คุณสร้างอินสแตนซ์ใหม่ได้โดยการนำฟิลด์บางส่วนจากฟิลด์ที่มีอยู่มาใช้ซ้ำ ..otro_struct.
ลอส เมนส์ สิ่งเหล่านี้เป็นเสาหลักสำคัญอีกประการหนึ่ง ช่วยให้คุณสามารถกำหนดประเภทข้อมูลที่สามารถเป็นหนึ่งในตัวแปรที่เป็นไปได้หลายแบบ โดยแต่ละแบบจะมีข้อมูลที่เกี่ยวข้องหรือไม่มีก็ได้ ตัวอย่างคลาสสิกคือ enum สำหรับที่อยู่ IP ที่มีตัวแปรหนึ่งตัว V4 ซึ่งเก็บสี่อ็อกเต็ตและอีกอันหนึ่ง V6 ซึ่งเก็บสตริงตามรูปแบบ IPv6
ไลบรารีมาตรฐานของ Rust ประกอบด้วยค่า enum ที่สำคัญสองตัว: Option<T> y Result<T, E>ตัวแรกแสดงถึงการมีอยู่หรือไม่มีอยู่ของค่า (บางสิ่งหรือไม่มีอะไรเลย) และใช้เพื่อหลีกเลี่ยงตัวชี้ว่าง ตัวที่สองแสดงการดำเนินการแบบจำลองที่สามารถ กลับผลลัพธ์ที่ถูกต้องหรือข้อผิดพลาดโดยกำหนดให้การจัดการข้อผิดพลาดต้องชัดเจนและปลอดภัย
เพื่อจัดการหน่วยความจำแบบไดนามิกและแบ่งปันข้อมูล Rust มี ตัวชี้อัจฉริยะ ในขณะที่ Box<T>ซึ่งจะย้ายค่าไปที่ฮีปและรักษาความเป็นเจ้าของที่ไม่ซ้ำกัน Rc<T>จำนวนการอ้างอิงที่ใช้ร่วมกันสำหรับสภาพแวดล้อมแบบเธรดเดียว และ Arc<T>คล้ายกับ Rc แต่ปลอดภัยสำหรับเธรดหลายเธรด การใช้อย่างถูกต้องเป็นสิ่งสำคัญเมื่อรวมหน่วยความจำแบบไดนามิกเข้ากับการทำงานพร้อมกัน
ระบบนิเวศสินค้าและลังไม้
Cargo คือกาวที่ยึดระบบนิเวศ Rust เข้าด้วยกัน: จัดการการรวบรวม การอ้างอิง และวงจรชีวิตของโครงการแต่ละโครงการจะมีไฟล์ Cargo.toml ซึ่งทำหน้าที่เป็น manifest โดยประกาศชื่อ เวอร์ชัน รุ่นภาษา และการอ้างอิงภายนอก
ส่วน ไฟล์นี้ช่วยให้คุณแสดงรายการลังของบุคคลที่สามพร้อมเวอร์ชัน เมื่อคุณรัน cargo build o cargo runCargo จะดาวน์โหลดกล่องเหล่านี้จาก crates.io โดยอัตโนมัติ คอมไพล์ และลิงก์ไปยังโปรเจกต์ของคุณ การเพิ่มเครื่องมือต่างๆ เช่น ตัวสร้างตัวเลขสุ่ม เฟรมเวิร์กเว็บ หรือไลบรารีการเข้ารหัสก็ทำได้ง่ายแสนง่าย
คำสั่งที่พบบ่อยที่สุดได้แก่ cargo new เพื่อเริ่มต้นโครงการไบนารี o cargo new --lib สำหรับห้องสมุด; cargo build เพื่อคอมไพล์ในโหมดดีบัก cargo build --release เพื่อให้ได้เวอร์ชันที่ปรับให้เหมาะสมและเน้นการผลิต cargo test เพื่อรันแบตเตอรี่การทดสอบ
cargo check สมควรได้รับการกล่าวถึงเป็นพิเศษ: มันคอมไพล์โค้ดจนถึงจุดกึ่งกลางโดยไม่สร้างไบนารี ซึ่งทำให้ ตรวจจับข้อผิดพลาดในการคอมไพล์ได้เร็วมากเหมาะอย่างยิ่งสำหรับการทำซ้ำอย่างรวดเร็วในขณะที่ตัวตรวจสอบการยืมชี้ให้เห็นปัญหาเกี่ยวกับคุณสมบัติ การอ้างอิง และอายุการใช้งาน
ด้วยระบบนิเวศนี้ ทำให้การจัดโครงสร้างโปรเจกต์ของคุณเป็นลังขนาดเล็กที่มีการกำหนดไว้อย่างชัดเจน การแบ่งปันโค้ดระหว่างกัน และการนำโซลูชันที่สร้างโดยชุมชนกลับมาใช้ใหม่ได้นั้นเป็นเรื่องปกติ ยกตัวอย่างเช่น สำหรับการทำงานพร้อมกันขั้นสูง คุณจะมีลังอย่าง Tokio สำหรับการเขียนโปรแกรมแบบอะซิงโครนัส หรือ crossbeam สำหรับโครงสร้างข้อมูลพร้อมกันประสิทธิภาพสูง
การทำงานพร้อมกันใน Rust: เธรด มิวเท็กซ์ แชนเนล และอะตอมิก
การทำงานพร้อมกันเป็นสาเหตุประการหนึ่งที่ทำให้ Rust ได้รับความสนใจมาก เนื่องจากช่วยให้คุณสามารถใช้ประโยชน์จากโปรเซสเซอร์แบบมัลติคอร์ได้ โดยไม่ตกอยู่ในข้อผิดพลาดทั่วไปของเธรดและหน่วยความจำที่ใช้ร่วมกันหากนี่เป็นครั้งแรกของคุณในการเรียนรู้หัวข้อเหล่านี้ จะเป็นประโยชน์หากสามารถแยกแยะแนวคิดหลายๆ แนวคิดออกจากกันได้
การทำงานพร้อมกัน (Concurrency) เกี่ยวข้องกับการดำเนินการหลายงานที่ทับซ้อนกันในเวลา ไม่ว่าจะบนคอร์เดียวหรือหลายคอร์ ใน Rust คุณสามารถสร้างเธรดของระบบเพื่อทำงานแบบขนานได้ และภาษาจะแนะนำคุณเพื่อให้แน่ใจว่าการแบ่งปันข้อมูลระหว่างเธรดเหล่านั้นมีความปลอดภัย ข้อผิดพลาดทั่วไปคือสภาวะการแข่งขัน (race condition) ซึ่งเธรดสองเธรดเข้าถึงและแก้ไขข้อมูลพร้อมกัน และผลลัพธ์จะขึ้นอยู่กับลำดับการดำเนินการ ซึ่งเป็นสิ่งที่แก้ไขได้ยากมาก
เพื่อประสานการเข้าถึงข้อมูลที่แชร์ Rust จะต้องอาศัยพื้นฐาน เช่น มิวเท็กซ์ซึ่งรับประกันการแยกกัน: มีเพียงเธรดเดียวเท่านั้นที่สามารถเข้าสู่ส่วนสำคัญได้ในแต่ละครั้ง เมื่อใช้ร่วมกับ Arc<T> ในการแบ่งปันความเป็นเจ้าของระหว่างเธรด เป็นไปได้ที่จะสร้างโครงสร้างข้อมูลที่ใช้ร่วมกันซึ่งปฏิบัติตามกฎของความเป็นเจ้าของและการยืม
รูปแบบการสื่อสารแบบอินเตอร์เธรดทั่วไปอีกแบบหนึ่ง ซึ่งได้รับการสนับสนุนอย่างมากใน Rust คือการส่งข้อความโดยใช้ ช่องช่องทางหนึ่งมีปลายทางการส่งและปลายทางการรับ โดยเธรดจะส่งข้อความ (ค่า) ผ่านช่องทางนั้น ซึ่งจะช่วยลดการใช้หน่วยความจำร่วมแบบเปลี่ยนแปลงได้ และทำให้การใช้เหตุผลเกี่ยวกับสถานะของระบบง่ายขึ้น
เมื่อคุณเจาะลึกลงไปในการทำงานพร้อมกันในระดับต่ำ จะปรากฏสิ่งต่อไปนี้: ประเภทอะตอมตัวแปรอะตอมมิกสามารถเข้าถึงได้ผ่านการดำเนินการที่แยกออกจากกันไม่ได้จากมุมมองของเธรด ซึ่งช่วยให้สามารถใช้งานตัวนับที่ใช้ร่วมกัน แฟล็กสถานะ คิวที่ไม่มีการล็อก และอื่นๆ ได้ การเรียนรู้ตัวแปรอะตอมมิกให้เชี่ยวชาญจำเป็นต้องเข้าใจโมเดลหน่วยความจำและคำสั่งการเข้าถึง ดังนั้นนักพัฒนาหลายคนจึงนิยมเริ่มต้นด้วยมิวเท็กซ์และแชนเนลก่อนที่จะลงลึกในรายละเอียดเหล่านี้
ขั้นตอนแรกและทรัพยากรสำหรับการเรียนรู้การทำงานพร้อมกันและอะตอม
หากคุณเข้าสู่สนามโดยไม่มีประสบการณ์มาก่อน แนวทางที่ชาญฉลาดที่สุดคือ สร้างรากฐานที่มั่นคงของแนวคิดทั่วไป ก่อนที่จะเริ่มใช้เครื่องมือขั้นสูงอย่างประเภทอะตอมของ Rust หนังสืออย่าง "Programming Rust" นำเสนอบทนำแบบค่อยเป็นค่อยไป แต่เป็นเรื่องปกติที่งานที่เน้นประเภทอะตอมและล็อกจะดูซับซ้อนในตอนแรก
เพื่อความสะดวกยิ่งขึ้น ขอแนะนำให้ทำความคุ้นเคยกับสิ่งนี้ก่อน เธรดแบบดั้งเดิม การกีดกันซึ่งกันและกัน และการส่งต่อข้อความ ใน Rust เล่นกับตัวอย่างของ std::thread, std::sync::Mutex, std::sync::Arc และช่องทางของ std::sync::mpsc ช่วยให้คุณเข้าใจว่าคอมไพเลอร์แนะนำคุณอย่างไรและหลีกเลี่ยงข้อผิดพลาดใดบ้าง
ในขณะเดียวกัน ขอแนะนำอย่างยิ่งให้ทบทวนทรัพยากรเบื้องต้นเกี่ยวกับการทำงานพร้อมกันโดยทั่วไป แม้ว่าจะไม่ได้เน้นที่ Rust ก็ตาม: ทำความเข้าใจว่าเงื่อนไขการแข่งขันคืออะไร การบล็อกหมายถึงอะไร หน่วยความจำที่ใช้ร่วมกันหมายถึงอะไรเมื่อเทียบกับการส่งข้อความ และใช้ล็อกอย่างไร เมื่อแนวคิดเหล่านั้นกลายเป็นเรื่องธรรมชาติสำหรับคุณแล้ว ฟิสิกส์อะตอมก็จะไม่ใช่ "เวทมนตร์ดำ" อีกต่อไป และพวกมันก็กลายเป็นเพียงเครื่องมืออีกชิ้นหนึ่งเท่านั้น แต่เป็นเครื่องมือที่ละเอียดอ่อนมาก
เมื่อคุณกลับไปดูข้อความขั้นสูงเกี่ยวกับอะตอมและล็อกใน Rust คุณจะสามารถติดตามการใช้เหตุผลได้ง่ายขึ้นมากหากคุณเข้าใจอยู่แล้วว่าโครงสร้างแต่ละอันกำลังพยายามแก้ไขอะไร ตั้งแต่เคาน์เตอร์ที่ปลอดภัยต่อเธรดแบบง่ายๆ ไปจนถึงโครงสร้างที่ไม่มีการล็อกซึ่งลดการโต้แย้งให้น้อยที่สุด
ท้ายที่สุด Rust นำเสนอทั้งไพรมิทีฟระดับสูงและเครื่องมือระดับต่ำมาก และสิ่งสำคัญคือการเลือกระดับการแยกส่วนที่ปลอดภัยที่สุดเสมอเพื่อแก้ไขปัญหาของคุณ โดยหันมาใช้โค้ดแบบอะตอม unsafe เมื่อมันเพิ่มมูลค่าได้จริงเท่านั้น และคุณเข้าใจถึงผลที่ตามมาอย่างถ่องแท้
ระบบนิเวศทั้งหมดนี้ของประเภท ความเป็นเจ้าของ การยืม กล่อง เครื่องมือ และการทำงานพร้อมกันแบบพื้นฐานรวมกันเพื่อเสนอภาษาในการเขียน ซอฟต์แวร์ที่รวดเร็ว แข็งแกร่ง และบำรุงรักษาได้วิธีนี้ช่วยลดข้อผิดพลาดหลายประเภทที่เคยรบกวนการเขียนโปรแกรมระบบมาโดยตลอด เมื่อคุณฝึกฝนกับโปรเจกต์เล็กๆ แบบฝึกหัดอย่าง Rustlings และเอกสารอย่างเป็นทางการ แนวคิดเหล่านี้จะเปลี่ยนจากกฎเกณฑ์ที่เคร่งครัดไปเป็นพันธมิตรที่คอยเตือนคุณก่อนที่ปัญหาจะลุกลามถึงการใช้งานจริง
นักเขียนผู้หลงใหลเกี่ยวกับโลกแห่งไบต์และเทคโนโลยีโดยทั่วไป ฉันชอบแบ่งปันความรู้ผ่านการเขียน และนั่นคือสิ่งที่ฉันจะทำในบล็อกนี้ เพื่อแสดงให้คุณเห็นสิ่งที่น่าสนใจที่สุดเกี่ยวกับอุปกรณ์ ซอฟต์แวร์ ฮาร์ดแวร์ แนวโน้มทางเทคโนโลยี และอื่นๆ เป้าหมายของฉันคือการช่วยคุณนำทางโลกดิจิทัลด้วยวิธีที่เรียบง่ายและสนุกสนาน