#![deny(warnings)]
คำอธิบาย
ผู้พัฒนา crate ด้วยความหวังดีต้องการให้มั่นใจว่าโค้ดของตนจะคอมไพล์ผ่านโดยไม่มีคำเตือน (warning) ใดๆ จึงได้ใส่ attribute ไว้ที่ crate root ดังนี้:
ตัวอย่าง
#![allow(unused)]
#![deny(warnings)]
fn main() {
// All is well.
}
ข้อดี
สั้น กระชับ และจะหยุดการบิลด์ทันทีหากมีจุดใดผิดปกติหรือไม่เป็นไปตามมาตรฐาน
ข้อเสีย
การไม่อนุญาตให้คอมไพเลอร์บิลด์ผ่านเมื่อมีคำเตือน เท่ากับว่าผู้พัฒนา crate กำลังปฏิเสธหลักประกันความเสถียร (stability guarantee) อันเลื่องชื่อของภาษา Rust ไปโดยปริยาย เนื่องจากในบางครั้ง เมื่อมีการเพิ่มฟีเจอร์ใหม่หรือต้องการแก้ไขข้อบกพร่องในฟีเจอร์เก่าที่ออกแบบมาไม่รัดกุม ทีมพัฒนา Rust จึงจำเป็นต้องเปลี่ยนแนวทางการทำงาน โดยสร้าง lint ที่แสดงข้อความเตือน (warn) ในช่วงระยะเวลาผ่อนผันก่อน เพื่อให้เวลาผู้พัฒนาปรับตัว ก่อนที่จะยกระดับให้กลายเป็นข้อผิดพลาดที่ไม่อนุญาตให้คอมไพล์ผ่าน (deny) ในภายหลัง
ตัวอย่างเช่น เคยมีการค้นพบว่าชนิดข้อมูลหนึ่งสามารถมีบล็อก impl สองบล็อกที่มีชื่อเมท็อดซ้ำกันได้ ซึ่งถูกมองว่าเป็นการออกแบบที่ไม่ดี แต่เพื่อให้การเปลี่ยนผ่านเป็นไปอย่างราบรื่น ทีมงานจึงได้เพิ่ม lint overlapping-inherent-impls เข้ามาเพื่อแสดงคำเตือนสำหรับผู้ที่เผลอเขียนโค้ดลักษณะนี้ ก่อนที่มันจะกลายเป็น error ร้ายแรงที่คอมไพล์ไม่ผ่าน (hard compile error) ในรีลีสถัดๆ ไป
นอกจากนี้ ในบางครั้ง API เก่าอาจถูกประกาศเลิกใช้งาน (deprecated) ซึ่งจะส่งผลให้การเรียกใช้ API นั้นเกิดคำเตือนขึ้นมา ทั้งที่ก่อนหน้านี้ไม่เคยมีคำเตือนมาก่อน
ปัจจัยเหล่านี้ล้วนส่งผลร่วมกันจนทำให้การบิลด์โค้ดอาจพังลงได้ทุกเมื่อที่มีการอัปเดตเวอร์ชันของคอมไพเลอร์หรือไลบรารี
ยิ่งไปกว่านั้น crate ที่มี lint เพิ่มเติมสำหรับตรวจสอบโค้ด (เช่น rust-clippy) ก็จะไม่สามารถนำมาใช้งานได้อีกต่อไป เว้นแต่ว่าจะลบ attribute ดังกล่าวออกก่อน อย่างไรก็ตาม ปัญหานี้สามารถบรรเทาได้ด้วยแฟล็ก –cap-lints โดยการส่งอาร์กิวเมนต์ --cap-lints=warn ในคำสั่งคอมไพล์ จะช่วยแปลง error ที่เกิดจาก lint ระดับ deny ทั้งหมดให้กลายเป็นเพียงคำเตือนธรรมดาได้
ทางเลือกอื่น
เราสามารถรับมือกับปัญหานี้ได้ 2 แนวทาง: แนวทางแรกคือแยกการตั้งค่าการบิลด์ออกจากตัวโค้ด และแนวทางที่สองคือระบุชื่อ lint ที่ต้องการสั่ง deny ไว้อย่างชัดเจนเป็นรายตัว
คำสั่งต่อไปนี้จะสั่งบิลด์โดยกำหนดให้คำเตือนทั้งหมดกลายเป็น deny ผ่านสภาพแวดล้อมภายนอก:
RUSTFLAGS="-D warnings" cargo build
นักพัฒนาแต่ละคนสามารถเรียกใช้คำสั่งนี้ได้ด้วยตนเอง (หรือจะตั้งค่าไว้ในเครื่องมือ CI เช่น Travis CI แต่โปรดระลึกไว้เสมอว่าการตั้งค่านี้อาจทำให้การบิลด์ใน CI พังได้เมื่อมีการอัปเดตเวอร์ชันใหม่) โดยไม่จำเป็นต้องเข้าไปแตะต้องหรือแก้ไขโค้ดเลย
หรืออีกทางเลือกหนึ่ง เราสามารถระบุ lint ที่ต้องการ deny ไว้ในโค้ดอย่างเจาะจง นี่คือรายการของ warning lint ที่ (น่าจะ) ปลอดภัยต่อการกำหนดเป็น deny (ข้อมูล ณ rustc 1.48.0):
#![deny(
bad_style,
const_err,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true
)]
นอกจากนี้ lint ที่เดิมมีสถานะเป็น allow ต่อไปนี้ อาจเป็นความคิดที่ดีหากจะนำมาตั้งเป็น deny:
#![deny(
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results
)]
บางคนอาจต้องการเพิ่ม missing-copy-implementations เข้าไปในรายการนี้ด้วยเช่นกัน
สังเกตว่าเราจงใจไม่ใส่ lint deprecated ไว้ในรายการนี้ เนื่องจากค่อนข้างแน่นอนว่าในอนาคตจะมี API อื่นๆ ถูกประกาศเลิกใช้งานเพิ่มเติมอีกเรื่อยๆ
ดูเพิ่มเติม
- รวม lint ทั้งหมดของ clippy
- เอกสารประกอบของ deprecate attribute
- พิมพ์คำสั่ง
rustc -W helpเพื่อดูรายการ lint ทั้งหมดในเครื่องของคุณ และพิมพ์rustc --helpเพื่อดูตัวเลือกคำสั่งทั่วไป - rust-clippy ชุดเครื่องมือ lint เพื่อการเขียนโค้ด Rust ที่มีคุณภาพยิ่งขึ้น