ว่าจะเขียนในเฟส แต่ยาวแล้ว formatting ในเฟสคนคงอ่านไม่รู้เรื่อง เลยเขียนในบล็อคละกัน
Cargo
- งงชื่อไฟล์มาก คือตอนแรกนึกว่าตั้งชื่อไฟล์มั่วๆ ได้ ปรากฏว่าไม่ใช่ มันมีชื่อไฟล์บังคับ src/main.rs src/lib.rs เข้าใจว่ามาจาก cargo เลยไม่อยู่ในเอกสารของ rust – -!!
- งง import ต่อ คือถ้าใช้ library ภายนอก ต้องประกาศ
extern crate
ที่ไฟล์ main ไม่ใช่ไฟล์ที่จะใช้ ในไฟล์ที่จะใช้ให้ใช้คำสั่ง use อย่างเดียว - นั่นแปลว่าถ้าใช้ในไฟล์ main ต้องย้ำ
extern crate ..; use ..;
ฮ่วย - เป็น package manager ที่เป็น build tool ด้วย เราว่าโอเคดี ยกเว้นแต่ว่ามันระบุ option rustc ตรงๆ ไม่ได้ (ว่าจะลอง
-C target-cpu=native
) - เขียน C แล้วเอา rust เรียก C ง่ายมาก ตัว cargo มันจะ compile C ให้ในขั้นตอน build เลยด้วย ไม่ต้องทำแยกกัน
- ปัญหาอย่างเดียวคือ C String เป็น 0 terminate แต่ rust string เป็น vector (เข้าใจว่า C++ ก็ใช้ vector เป็น string?) เวลาแปลงข้ามไปมาก็สนุกเลย
Data type
- คอมไพล์ไม่ผ่านบ่อยมาก ครึ่งวันน่าจะหมดไปกับแก้ compile error
- คอมไพล์เสร็จตามที่เค้าโม้ครับคือคุณไม่มีทาง segmentation fault ได้จริงๆ
- การ proof ให้ rust เชื่อว่า memory safe มหาโหดมาก
- ในภาษาปกติ
let a = b;
นี่แปลว่าa
มีค่าเหมือนกับb
แต่ใน rust มันแปลว่าเลิกใช้b
ได้เลย เพราะa
เป็นเจ้าของค่าในb
แล้ว และค่าหนึ่งมีเจ้าของคนเดียว - เดี๋ยวมีต่อด้านล่างว่ามันทำให้ optimize ไม่ได้ด้วย
- ในภาษาปกติ
- ที่ตลกมาก คืออ่าน struct จากไฟล์ทำไม่ได้… เหตุผล เพราะคุณแน่ใจได้ยังไงว่าอ่านมาแล้ว struct ในไฟล์มันตรงกับ memory layout คุณจริง
- ผลคือ ไปเขียนตัวอ่าน struct ใน C มาแล้วคอมไพล์เข้ามาเป็น rust เขียนง่ายกว่า ไม่งั้นคุณต้องมานั่ง proof ให้ rust เชื่อเรื่อง data type มหาศาล
- Type inference ของ rust โคตรเก่ง ยอมรับเลย คือนอกจากตรงที่ภาษาบังคับแทบจะไม่ต้องระบุ data type เลย
- Compiler บังคับ coding standard ด้วย คุณจะต้องใช้
under_score_function_name
ทั้งหมด ไม่งั้น warning -
rust string เป็น utf8 เท่านั้น ถ้าคุณจะใช้ encoding อื่นกรุณาเก็บใน
[u8]
(array ของ nt8_t) - ถ้าต้องการจะอ่าน uint_32 ในไฟล์ แต่
read
ของ rust มันอ่านเป็น[u8];
จะแปลงยังไง- คำตอบคือ
let id: u32 = unsafe{::std::mem::transmute_copy(& buffer);}
transmute_copy
คือบอกว่า pointer นั้นอะจริงๆ แล้วมันชี้ไปหา data type นี้นะ คือไม่มีการ cast อะไรทั้งสิ้น เปลี่ยนวิธีมองตำแหน่งใน memory เลย แต่ถึงจะบอกว่า unsafe มันก็ยังเช็คให้ว่า memory ตรงนั้น กับ data type ใหม่มีขนาดเท่ากัน
- คำตอบคือ
- rust ไม่มี null รู้สึกภาษาใหม่ๆ จะมาแนวนี้หมด ไม่ว่าจะ Kotlin หรือ swift คือจะใช้ระบบ Optional แทน
- ไอเดียคือฟังก์ชั่นต้องประกาศว่าฟังก์ชั่นนี้ return เป็น optional แล้วคนที่เรียกก็ต้องไปเช็คเสมอว่า return มามีค่าหรือเปล่า
- ข้อดีคือไม่เกิด null pointer แน่ๆ เพราะบังคับให้คุณเขียนจัดการ null
- ข้อเสีย if ทุก method call เลยมั้ยครับท่าน…
- Rust ไม่มี Class แต่ struct มี method ได้เรียกว่า implementation (สุดท้ายคือหน้าตาออกมาโคตรเหมือน class แค่ไม่มี inheritance)
- ไม่ใส่ ; ก็ได้ แต่การใส่
;
มีผล!!!! ผมนี่สตั้นเลย ลองดูโค้ดนี้นะครับ
fn x() -> u8 {
y();
}
fn x() -> u8 {
y()
}
- จะบอกว่าโค้ดแรก คอมไพล์ไม่ผ่าน ครับ เพราะมันถือว่ามี 2 statement คือ
y()
กับ statement เปล่า มันเลย return เป็นค่าว่างเปล่า (()
) ไป!!! ในขณะที่อันหลังมีแค่ statement เดียว ก็จะ return คำตอบของy()
(ตรงนี้คล้ายๆ ruby ที่ expression สุดท้ายของฟังก์ชั่นเป็น return value ของฟังก์ชั่นด้วย)
บ่น
ผมจะทำ object pool ก็เขียนมา
let record = Record{
id: 0,
text: ....,
};
อ่าว… แล้ว text เป็น String จะใส่ว่าอะไร… เอางี้ละกัน
let empty_string = String::new();
let mut record = Record{
id: 0,
text: empty_string,
};
loop{
reader.read_recycle(&mut record);
let text = record.text;
record.text = empty_string;
put_ds(text);
}
ปรากฏว่า empty_string อันหลังนั่นมันถือว่าบรรทัดที่ 3 ยึดเป็นเจ้าของไปแล้ว ใช้ไม่ได้ สุดท้ายก็เลยต้อง String::new()
สองรอบ นี่มันก็ไม่ต่างกับไม่ทำ object pool แล้วนะ!!
Speed
- สรุปแล้วถามว่า rust เร็วมั้ย คำตอบคือไม่ครับ มันเป็นห่วง memory safety เกินไป คือบางอันคุณเห็นกับตาว่าคุณไม่ใช้ แต่คุณพิสูจน์เป็นโค้ดให้ rust ไม่ได้คุณก็เขียนไม่ได้ แล้วมันทำให้ต้องมานั่งอ้อมโลกจนน่ารำคาญ
- แต่อย่าลืมนะครับว่ามันเป็นภาษา low level ฉะนั้นแล้วมันแค่ช้ากว่า C แค่นั้นแหละครับ….
เห็นการบังคับหลายอย่าง โดยเฉพาะเรื่อง underscore นี่ทำผมร้องเชรี่ยเลย
ผมคงรับแนวคิดมา แต่คงไม่ใช้ระบบนี้หรือกครับ บังคับกันเกิ๊น…