Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

#![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 ที่มีคุณภาพยิ่งขึ้น