นำเข้าเส้นทางสู่ขอบเขตการทำงานด้วยคีย์เวิร์ด use (Bringing Paths into Scope with the use Keyword)
การที่ต้องพิมพ์เขียนเส้นทางเต็ม ๆ ทุกครั้งที่ต้องการเรียกใช้งานฟังก์ชันอาจทำให้รู้สึกไม่สะดวกและมีความซ้ำซากจำเจ ในรายการโค้ดที่ 7-7 ไม่ว่าเราจะเลือกใช้เส้นทางแบบสัมบูรณ์หรือแบบสัมพัทธ์ไปยังฟังก์ชัน add_to_waitlist ทุกครั้งที่เราต้องการเรียกใช้งานฟังก์ชัน add_to_waitlist เราก็จำเป็นต้องพิมพ์คำว่า front_of_house และ hosting นำหน้าอยู่ดี แต่ทว่าโชคดีที่ภาษานี้มีวิธีการทำให้ขั้นตอนนี้ง่ายขึ้น: เราสามารถสร้างทางลัด (shortcut) ไปยังเส้นทางใด ๆ ด้วยการใช้คีย์เวิร์ด use เพียงครั้งเดียว และหลังจากนั้นจะสามารถเรียกใช้ชื่อย่อที่สั้นลงได้ในทุกจุดในขอบเขตการทำงาน (scope) นั้น
ในรายการโค้ดที่ 7-11 เราจะทำการนำโมดูล crate::front_of_house::hosting เข้าสู่ขอบเขตการทำงานของฟังก์ชัน eat_at_restaurant ซึ่งจะส่งผลให้เราเหลือเพียงระบุเส้นทางสั้น ๆ แค่ hosting::add_to_waitlist ในการเรียกใช้งานฟังก์ชัน add_to_waitlist ภายใน eat_at_restaurant
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
การใส่คำสั่ง use พร้อมระบุเส้นทางในขอบเขตการทำงานเปรียบเสมือนการสร้างลิงก์สัญลักษณ์ (symbolic link หรือ symlink) ในระบบไฟล์ข้อมูล ด้วยการเขียนคำสั่ง use crate::front_of_house::hosting ไว้ที่รากเครต ส่งผลให้ชื่อ hosting กลายเป็นชื่อที่ถูกต้องและเรียกใช้งานได้ในขอบเขตดังกล่าว เสมือนหนึ่งว่าโมดูล hosting นั้นได้รับการนิยามไว้ที่ระดับรากเครตโดยตรง และเส้นทางข้อมูลที่ถูกดึงเข้ามาใช้ผ่าน use ก็ยังคงผ่านการตรวจสอบความเป็นส่วนตัวตามปกติเหมือนกับเส้นทางอื่น ๆ
ข้อสังเกตคือ คีย์เวิร์ด use จะทำหน้าที่สร้างทางลัดเฉพาะสำหรับขอบเขตการทำงานเจาะจงที่มันปรากฏอยู่เท่านั้น ในรายการโค้ดที่ 7-12 ได้มีการย้ายฟังก์ชัน eat_at_restaurant เข้าไปอยู่ภายในโมดูลย่อยใหม่ชื่อ customer ซึ่งส่งผลให้มันอยู่คนละขอบเขตการทำงานกับคำสั่ง use ดังนั้นตัวฟังก์ชันจึงจะไม่สามารถคอมไพล์ผ่านได้
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}
ข้อผิดพลาดจากคอมไพเลอร์แสดงให้เห็นว่าทางลัดดังกล่าวไม่มีผลใช้งานภายในโมดูล customer อีกต่อไป:
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0433]: cannot find module or crate `hosting` in this scope
--> src/lib.rs:11:9
|
11 | hosting::add_to_waitlist();
| ^^^^^^^ use of unresolved module or unlinked crate `hosting`
|
= help: if you wanted to use a crate named `hosting`, use `cargo add hosting` to add it to your `Cargo.toml`
help: consider importing this module through its public re-export
|
10 + use crate::hosting;
|
warning: unused import: `crate::front_of_house::hosting`
--> src/lib.rs:7:5
|
7 | use crate::front_of_house::hosting;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
For more information about this error, try `rustc --explain E0433`.
warning: `restaurant` (lib) generated 1 warning
error: could not compile `restaurant` (lib) due to 1 previous error; 1 warning emitted
สังเกตว่าจะมีข้อความแจ้งเตือน (warning) ระบุว่าคำสั่ง use นั้นไม่มีการเรียกใช้งานภายในขอบเขตของมันแล้วเช่นกัน! ในการแก้ไขปัญหานี้ ให้คุณโยกย้ายบรรทัดคำสั่ง use เข้าไปเขียนไว้ภายในโมดูล customer ด้วย หรือไม่ก็อ้างอิงถึงทางลัดในโมดูลหลักภายนอกด้วยการใช้เส้นทาง super::hosting จากภายในโมดูลย่อย customer แทน
การสร้างเส้นทางด้วย use ตามรูปแบบที่เหมาะสม (Creating Idiomatic use Paths)
จากรายการโค้ดที่ 7-11 คุณอาจจะสงสัยว่าทำไมเราจึงกำหนด use crate::front_of_house::hosting แล้วค่อยสั่งเรียก hosting::add_to_waitlist ใน eat_at_restaurant แทนที่จะระบุเส้นทางใน use ยาวไปจนถึงตัวฟังก์ชัน add_to_waitlist โดยตรงเพื่อให้ได้ผลลัพธ์แบบเดียวกัน ดังแสดงในรายการโค้ดที่ 7-13
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
add_to_waitlist();
}
แม้ว่าโค้ดทั้งในรายการโค้ดที่ 7-11 และรายการโค้ดที่ 7-13 จะสามารถทำงานได้สำเร็จลุล่วงเหมือนกัน แต่ทว่ารายการโค้ดที่ 7-11 ถือเป็นวิธีที่เหมาะสมตามหลักปฏิบัตินิยม (idiomatic way) ในการนำฟังก์ชันเข้าสู่ขอบเขตการทำงานด้วย use การนำโมดูลหลักของฟังก์ชันเข้าสู่ขอบเขตการทำงานหมายถึงเราต้องเขียนระบุชื่อโมดูลหลักนำหน้าฟังก์ชันเมื่อเรียกใช้ การทำแบบนี้จะทำให้โค้ดระบุได้อย่างชัดเจนว่าฟังก์ชันดังกล่าวไม่ได้ประกาศนิยามอยู่ภายในพื้นที่ปัจจุบันของมันเอง ในขณะที่ยังคงช่วยประหยัดการเขียนพิมพ์เส้นทางเต็ม ๆ ซ้ำซาก โค้ดในรายการโค้ดที่ 7-13 นั้นไม่ชัดเจนว่าตัวฟังก์ชัน add_to_waitlist ถูกนิยามไว้ที่ส่วนใดของระบบ
ในทางกลับกัน เมื่อคุณต้องการนำเข้า structs, enums หรือไอเท็มข้อมูลอื่น ๆ เข้ามาด้วย use วิธีปฏิบัติที่เหมาะสมคือการระบุเส้นทางไปจนถึงตัวไอเท็มชิ้นนั้น ๆ โดยตรงเลย รายการโค้ดที่ 7-14 แสดงวิธีการนำ struct HashMap จากไลบรารีมาตรฐานเข้าสู่ขอบเขตการทำงานของเครตฐานสองตามรูปแบบที่นิยมปฏิบัติกัน:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}
ไม่มีเหตุผลเบื้องหลังที่สลักสำคัญมากนักสำหรับรูปแบบแนวคิดนี้ มันเป็นเพียงธรรมเนียมปฏิบัติร่วมกันที่พัฒนาขึ้นมา และนักเขียนโปรแกรมต่างเริ่มมีความคุ้นชินกับการอ่านและเขียนโค้ดภาษา Rust ในลักษณะนี้ไปแล้ว
ข้อยกเว้นเพียงอย่างเดียวของแนวทางปฏิบัตินี้คือ ยามที่เราจำเป็นต้องนำเข้าไอเท็มสองชิ้นที่มีชื่อพ้องกันเข้าสู่ขอบเขตการทำงานเดียวกันด้วยคำสั่ง use เนื่องจากระบบของ Rust ไม่อนุญาตให้ทำเช่นนั้นได้ รายการโค้ดที่ 7-15 แสดงวิธีการนำเข้าชนิดข้อมูล Result สองตัวที่มีชื่อเหมือนกันแต่มีโมดูลหลักต่างกันเข้าสู่ขอบเขตเดียวกัน และวิธีการเขียนเพื่อเรียกใช้งานพวกมัน:
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
Ok(())
}
fn function2() -> io::Result<()> {
// --snip--
Ok(())
}
ดังที่เห็น การใช้โมดูลหลักนำหน้าจะช่วยคั่นแบ่งชนิดข้อมูล Result ทั้งสองประเภทออกจากกันได้ชัดเจน หากเราเขียนระบุเป็น use std::fmt::Result and use std::io::Result คู่กัน เราจะมีชนิดข้อมูล Result สองตัวปนอยู่ในขอบเขตเดียวกัน ซึ่งจะส่งผลให้ Rust ไม่สามารถจำแนกออกได้ว่าเราหมายถึงตัวใดเมื่อมีการเรียกคำว่า Result
การตั้งชื่อใหม่ให้กับชนิดข้อมูลด้วยคีย์เวิร์ด as (Providing New Names with the as Keyword)
มีอีกหนึ่งแนวทางในการแก้ไขปัญหาเรื่องชื่อที่พ้องกันยามนำเข้าสู่ขอบเขตเดียวกันผ่าน use คือ การพิมพ์เขียนคำสั่ง as ต่อท้ายเส้นทางเพื่อระบุชื่อเรียกใหม่เฉพาะที่ หรือ นามแฝง (alias) ให้แก่ชนิดข้อมูลนั้น ๆ รายการโค้ดที่ 7-16 แสดงวิธีการเขียนโค้ดในรายการโค้ดที่ 7-15 อีกแบบ โดยการเปลี่ยนชื่อเรียกของหนึ่งในชนิดข้อมูล Result ผ่านคีย์เวิร์ด as:
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
Ok(())
}
fn function2() -> IoResult<()> {
// --snip--
Ok(())
}
ในคำสั่ง use บรรทัดที่สอง เราได้เลือกตั้งชื่อใหม่ว่า IoResult ให้กับชนิดข้อมูล std::io::Result ซึ่งจะไม่ขัดแย้งพ้องกับชื่อ Result จากโมดูล std::fmt ที่เรานำเข้ามาด้วย ทั้งแนวทางในรายการโค้ดที่ 7-15 และรายการโค้ดที่ 7-16 ล้วนได้รับการยอมรับว่าถูกต้องและเหมาะสมตามหลักปฏิบัติ ดังนั้นการเลือกใช้งานจึงขึ้นอยู่กับความชอบส่วนบุคคลของคุณเอง!
การส่งออกชื่อไอเท็มซ้ำด้วย pub use (Re-exporting Names with pub use)
เมื่อเรานำเข้าชื่อไอเท็มสู่ขอบเขตการทำงานผ่านคีย์เวิร์ด use ชื่อดังกล่าวจะมีสถานะเป็นแบบส่วนตัวเฉพาะสำหรับขอบเขตที่ได้รับนำเข้าเท่านั้น เพื่ออนุญาตให้โค้ดภายนอกขอบเขตสามารถอ้างอิงและเรียกใช้ชื่อนั้นได้เสมือนว่าชื่อดังกล่าวได้รับการประกาศนิยามขึ้นภายในขอบเขตนั้นตั้งแต่แรก เราสามารถนำเอาคีย์เวิร์ด pub และ use มารวมพลังใช้งานร่วมกัน เทคนิคนี้เรียกว่า การส่งออกซ้ำ (re-exporting) เนื่องจากเราทำหน้าที่นำไอเท็มเข้าสู่ขอบเขตการทำงานพร้อมทั้งเปิดทางให้บุคคลอื่นสามารถดึงเอาไอเท็มนั้นไปใช้ในขอบเขตการทำงานของตนเองได้ด้วย
รายการโค้ดที่ 7-17 แสดงโค้ดในรายการโค้ดที่ 7-11 โดยเปลี่ยนคำสั่ง use ในโมดูลรากเครตให้กลายเป็น pub use
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
ก่อนที่จะทำการแก้ไขเรื่องนี้ โค้ดภายนอกจำเป็นจะต้องเรียกใช้งานฟังก์ชัน add_to_waitlist ผ่านทางเส้นทางยาว ๆ อย่าง restaurant::front_of_house::hosting::add_to_waitlist() ซึ่งหมายความว่าจะต้องกำหนดให้โมดูล front_of_house เป็นแบบสาธารณะ (pub) ด้วย แต่เมื่อเรานำเอา pub use มาใช้ส่งออกโมดูล hosting ซ้ำจากระดับโมดูลรากแล้ว โค้ดภายนอกจะสามารถหันมาเรียกใช้ผ่านเส้นทางที่สั้นลงอย่าง restaurant::hosting::add_to_waitlist() ได้ทันที
การส่งออกซ้ำมีประโยชน์อย่างมากในยามที่โครงสร้างการจัดเก็บโค้ดภายในระบบของคุณ มีความแตกต่างไปจากมุมมองที่โปรแกรมเมอร์ผู้นำโค้ดของคุณไปใช้คาดเดาไว้ ตัวอย่างเช่น ในการเปรียบเทียบเรื่องร้านอาหารนี้ บุคลากรผู้ดูแลร้านจะคิดถึงโครงสร้างแบบ “หน้าร้าน (front of house)” และ “หลังร้าน (back of house)” แต่ทว่าลูกค้าที่เดินเข้าร้านคงจะไม่ได้คิดหรือมองเห็นโครงสร้างร้านอาหารในแง่มุมเหล่านั้น การเลือกใช้ pub use จึงช่วยให้เราสามารถออกแบบโครงสร้างโค้ดภายในรูปแบบหนึ่ง แต่เลือกแสดงผลให้ภายนอกเห็นเป็นโครงสร้างอีกรูปแบบหนึ่งได้ ซึ่งการทำเช่นนี้จะช่วยให้เครตห้องสมุดของเรามีความเป็นระเบียบเรียบร้อยทั้งสำหรับโปรแกรมเมอร์ผู้ทำหน้าที่พัฒนาห้องสมุด และโปรแกรมเมอร์ผู้นำห้องสมุดไปเรียกใช้งาน เราจะมาศึกษาตัวอย่างของการใช้ pub use และวิธีการส่งผลกระทบต่อเอกสารอ้างอิง (documentation) ของเครตของคุณเพิ่มเติมในหัวข้อ“ส่งออก API สาธารณะเพื่อความสะดวกในการใช้งาน” ในบทที่ 14
การใช้งานแพ็กเกจภายนอก (Using External Packages)
ในบทที่ 2 เราได้เคยร่วมกันพัฒนาโปรแกรมทายตัวเลขซึ่งมีระบบดึงเอาแพ็กเกจภายนอกที่ชื่อว่า rand มาช่วยในการสุ่มตัวเลข โดยในการเรียกใช้งาน rand ในโปรเจกต์ของเรานั้น เราได้พิมพ์เขียนบรรทัดด้านล่างนี้ลงในไฟล์ Cargo.toml:
rand = "0.10.1"
การใส่ชื่อ rand ในฟิลด์ dependencies ของไฟล์ Cargo.toml จะเป็นการแจ้งบอก Cargo ให้ทำหน้าที่ดาวน์โหลดแพ็กเกจ rand และโปรแกรมที่เกี่ยวข้องอื่น ๆ จากฐานข้อมูลกลาง crates.io และทำหน้าที่จัดเตรียม rand ให้พร้อมสำหรับใช้ในโปรเจกต์ของเรา
จากนั้น ในการนำคำประกาศของ rand เข้าสู่ขอบเขตการทำงานของแพ็กเกจเรา เราได้เขียนบรรทัดคำสั่ง use ที่เริ่มต้นด้วยชื่อของเครตคือ rand และระบุรายการไอเท็มย่อยที่เราต้องการนำเข้ามา ย้อนกลับไปพิจารณาเนื้อหาในส่วน“สร้างการสุ่มตัวเลข” ในบทที่ 2 เราได้ดึงเอาโมดูลย่อย rand::prelude เข้าสู่ขอบเขตการทำงานและสั่งเรียกใช้ฟังก์ชัน rand::rng:
use std::io;
use rand::prelude::*;
fn main() {
println!("Guess the number!");
let secret_number = rand::rng().random_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {guess}");
}
สมาชิกในชุมชนของภาษา Rust ได้มีการแบ่งปันผลงานแพ็กเกจต่าง ๆ มากมายไว้บนฐานข้อมูลกลาง crates.io ซึ่งการดึงเอาสิ่งเหล่านั้นเข้ามาใช้งานในโปรเจกต์ของคุณจะมีขั้นตอนการปฏิบัติที่คล้ายคลึงกัน คือ การระบุรายชื่อพวกมันลงในไฟล์ Cargo.toml ของคุณ และเขียนเรียกใช้ use เพื่อดึงเอาไอเท็มจากเครตเหล่านั้นเข้าสู่ขอบเขตการทำงาน
โปรดทราบว่าห้องสมุดมาตรฐาน std ก็มีสถานะเป็นเครตหนึ่งที่อยู่ภายนอกแพ็กเกจของเราเช่นเดียวกัน แต่เนื่องจากห้องสมุดมาตรฐานจะถูกแนบจัดส่งมาพร้อมกับตัวภาษา Rust ตั้งแต่แรกแล้ว เราจึงไม่มีความจำเป็นต้องไปเขียนแก้ไขไฟล์ Cargo.toml เพื่อดึงเอา std เข้ามาเพิ่ม แต่อย่างไรก็ตาม เรายังคงต้องเขียนระบุคำสั่ง use เพื่อดึงเอาไอเท็มข้อมูลต่าง ๆ ของมันเข้าสู่ขอบเขตงานของแพ็กเกจเรา ตัวอย่างเช่นการใช้ struct HashMap เราจะเขียนบรรทัดนี้:
#![allow(unused)]
fn main() {
use std::collections::HashMap;
}
นี่คือตัวอย่างของเส้นทางแบบสัมบูรณ์ที่ขึ้นต้นด้วยคำว่า std ซึ่งเป็นชื่อเฉพาะของเครตห้องสมุดมาตรฐาน
การใช้เส้นทางแบบซ้อนเพื่อจัดระเบียบรายการคำสั่ง use (Using Nested Paths to Clean Up use Lists)
หากโปรเจกต์ของเรามีการเรียกใช้งานไอเท็มข้อมูลหลายชิ้นที่มาจากเครตหรือโมดูลหลักตัวเดียวกัน การเขียนระบุบรรทัดคำสั่ง use แยกแยกบรรทัดกันจะใช้พื้นที่ในแนวตั้งของไฟล์ซอร์สโค้ดไปค่อนข้างมาก ตัวอย่างเช่น บรรทัดคำสั่ง use สองบรรทัดที่เราใช้ในโปรแกรมเกมทายตัวเลขในรายการโค้ดที่ 2-4 ที่ทำหน้าที่นำเข้าไอเท็มข้อมูลจาก std:
// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--
use rand::prelude::*;
fn main() {
println!("Guess the number!");
let secret_number = rand::rng().random_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
แต่ในทางกลับกัน เราสามารถเลือกใช้ระบบเส้นทางแบบซ้อน (nested paths) เพื่อดึงเอาไอเท็มเหล่านั้นเข้ามาสู่ขอบเขตงานได้พร้อมกันภายในบรรทัดเดียว โดยเราจะเขียนระบุส่วนของเส้นทางที่เป็นจุดร่วมกัน (common part) ตามด้วยโคลอนคู่ และวงเล็บปีกกาครอบกลุ่มไอเท็มย่อยที่มีความแตกต่างกันไว้ ดังที่แสดงในรายการโค้ดที่ 7-18
use rand::prelude::*;
// --snip--
use std::{cmp::Ordering, io};
// --snip--
fn main() {
println!("Guess the number!");
let secret_number = rand::rng().random_range(1..=100);
println!("The secret number is: {secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = guess.trim().parse().expect("Please type a number!");
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => println!("You win!"),
}
}
สำหรับโปรแกรมที่มีความใหญ่โตขึ้น การดึงเอาไอเท็มจำนวนมากที่สังกัดเครตหรือโมดูลเดียวกันเข้ามาด้วยระบบเส้นทางแบบซ้อนนี้ จะช่วยลดจำนวนบรรทัดคำสั่ง use ลงไปได้อย่างมหาศาลเลยทีเดียว!
เราสามารถใช้ประโยชน์จากเส้นทางแบบซ้อนในระดับใด ๆ ของเส้นทางก็ได้ ซึ่งจะมีประโยชน์มากเมื่อรวมคำสั่ง use สองบรรทัดที่มีเส้นทางย่อยร่วมกัน ตัวอย่างเช่น รายการโค้ดที่ 7-19 แสดงบรรทัดคำสั่ง use สองบรรทัด: บรรทัดแรกนำเข้า std::io และบรรทัดที่สองนำเข้า std::io::Write
use std::io;
use std::io::Write;
ส่วนเส้นทางที่เป็นจุดร่วมของทั้งคู่คือ std::io ซึ่งก็คือเส้นทางแบบเต็มในบรรทัดแรก ในการรวมทั้งสองเส้นทางนี้ให้กลายเป็นคำสั่ง use เพียงบรรทัดเดียว เราสามารถเขียนคำว่า self ในระบบเส้นทางซ้อนได้ ดังแสดงในรายการโค้ดที่ 7-20
use std::io::{self, Write};
คำสั่งบรรทัดนี้จะนำเข้าทั้ง std::io และ std::io::Write เข้าสู่ขอบเขตการทำงานพร้อมกัน
การนำเข้าไอเท็มต่าง ๆ ด้วยตัวดำเนินการดอกจัน (Importing Items with the Glob Operator)
หากเรามีความประสงค์ต้องการจะนำเข้าไอเท็มสาธารณะ ทั้งหมด ที่อยู่ภายในเส้นทางดังกล่าวเข้าสู่ขอบเขตการทำงาน เราสามารถระบุเส้นทางและตามหลังด้วยสัญลักษณ์ดอกจัน * (glob operator) ได้ดังนี้:
#![allow(unused)]
fn main() {
use std::collections::*;
}
บรรทัดคำสั่ง use นี้จะดึงเอาไอเท็มสาธารณะทั้งหมดที่ถูกนิยามไว้ใน std::collections เข้าสู่ขอบเขตการทำงานปัจจุบัน โปรดใช้ความระมัดระวังอย่างยิ่งในการเรียกใช้ตัวดำเนินการดอกจันนี้! เนื่องจากมันจะทำให้ตรวจสอบได้ยากขึ้นว่าชื่อของตัวแปรหรือฟังก์ชันใดบ้างที่ถูกนำเข้า และยากจะรู้ได้ว่าชื่อที่ถูกนำไปใช้ในโปรแกรมของคุณได้รับการประกาศขึ้นที่ใด นอกจากนี้ หากไลบรารีภายนอกมีการเปลี่ยนแปลงโครงสร้างคำจำกัดความ สิ่งที่คุณนำเข้ามาก็จะเปลี่ยนตามไปด้วย ซึ่งอาจส่งผลให้เกิดข้อผิดพลาดในการคอมไพล์ยามที่คุณอัปเกรดไลบรารีนั้นในอนาคต หากไลบรารีเพิ่มชื่อที่พ้องกันกับตัวแปรที่คุณประกาศใช้เองในขอบเขตเดียวกัน
ตัวดำเนินการดอกจันนี้มักถูกนำไปประยุกต์ใช้งานในขั้นตอนการเขียนชุดทดสอบ (testing) เพื่อดึงเอาทุกองค์ประกอบที่เกี่ยวข้องเข้ามาไว้ในโมดูล tests ซึ่งเราจะอธิบายเพิ่มเติมในหัวข้อ“วิธีการเขียนชุดทดสอบ” ในบทที่ 11 นอกจากนี้บางครั้งมันยังถูกนำไปใช้ร่วมกับรูปแบบโครงสร้าง prelude อีกด้วย สามารถเปิดอ่านรายละเอียดเพิ่มเติมเกี่ยวกับรูปแบบดังกล่าวได้ในเอกสารอ้างอิงของห้องสมุดมาตรฐาน