Rust程式語言強大的編譯器可以讓它在編譯階段時就去做完許多其它程式語言在執行階段才能進行的工作,像是Rust的標準函式庫,就有提供一個concat巨集,可以將任意數量定數(literal)直接串接成生命周期為'static的字串切片(&'static str)。



例如以下程式碼:

const ABC: &str = concat!("test", 10, 'b', true);

ABC是一個型別為&'static str的常數,其值等同於"test10btrue"

對於函式庫(library)的開發,concat巨集可能用不太到,但是如果是在開發應用程式(application),就很有機會需要在程式碼中撰寫大量的自然語句,concat巨集就可以用來「分段」這些語句,讓程式比較容易維護,且在執行時又不會有多餘的效能開支(overhead)。

不過在實務上,concat巨集用起來並不是很方便,因為它不能夠自動在每個定數之間、之前或是之後自動添加其它的字串(或是定數)。例如以逗號和空格, 來分隔每個定數,就只能自行在原本的每個定數間撰寫, ,像是下面這個程式碼:

const ABC: &str = concat!("test", ", ", 10, ", ", 'b', ", ", true);

以上程式,ABC常數的值等同於"test, 10, b, true"

Concat With

「Concat With」是筆者開發的套件,可以用以擴充標準函式庫內的concat巨集的功能,讓它可以在每個定數的之間、之前或是之後自動添加其它的字串(或是定數)。

Crates.io

https://crates.io/crates/concat-with

Cargo.toml

concat-with = "*"

巨集的使用方法

concat

這個concat_with crate,提供了與標準函數庫中的concat巨集同名的巨集,用法相容於標準函數庫中的concat巨集。但是,concat_withconcat巨集在撰寫定數之前,可以使用withprefixsuffix關鍵字來分別設定每個定數的之間、之前或是之後要自動添加什麼字串(或是定數)。

例如以逗號和空格, 來分隔每個定數,程式碼可以這樣寫:

#[marco_use]
extern crate concat_with;

const ABC: &str = concat!(with ", ", "test", 10, 'b', true);

再例如,以換行字元\n來分隔每個定數,並在每個定數前添加Someone says: ,程式碼可以這樣寫:

#[marco_use]
extern crate concat_with;

const ABC: &str = concat!(with "\n", prefix "Someone says: ", "Hello.", "Nice to meet you!");

以上程式,ABC常數的值為"Someone says: Hello.\nSomeone says: Nice to meet you!"

concat_line

concat_line巨集算是concat!(with "\n", ...)的語法糖(syntactic sugar),可以省下使用concat巨集時撰寫with "\n"的麻煩。

例如:

#[marco_use]
extern crate concat_with;

const ABC: &str = concat_line!(prefix "Someone says: ", "Hello.", "Nice to meet you!");

以上程式,ABC常數的值同樣為"Someone says: Hello.\nSomeone says: Nice to meet you!"

concat_impl

concat_impl巨集可以用來建立我們自己的巨集,像是concat_line巨集那樣在串接定數的同時以特定的定數作分隔,且支援前綴和後綴的插入。

extern crate concat_with;

#[doc(hidden)]
pub use concat_with::{concat, concat_impl}; // re-export `concat!` and `concat_impl!` if your custom macros use `#[macro_export]`

concat_impl! {
    #[macro_export]
    /// Concatenates literals into a static string slice separated by a comma, `,`. Prefixes and suffixes can also be added.
    concat_with_comma => ", ",
    #[macro_export]
    /// Concatenates literals into a static string slice separated by a colon, `:`. Prefixes and suffixes can also be added.
    concat_with_colon => ':',
}

assert_eq!("test, 10, b, true", concat_with_comma!("test", 10, 'b', true));
assert_eq!("test:10:b:true", concat_with_colon!("test", 10, 'b', true));