1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
//! 标准库宏
//!
//! 该模块包含一组从标准库导出的宏。
//! 当链接到标准库时,每个宏都可以使用。
//!
// ignore-tidy-dbg
#[doc = include_str!("../../core/src/macros/panic.md")]
#[macro_export]
#[rustc_builtin_macro(std_panic)]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(edition_panic)]
#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_macro")]
macro_rules! panic {
// 根据调用者的版本扩展为 `$crate::panic::panic_2015` 或 `$crate::panic::panic_2021`。
//
($($arg:tt)*) => {
/* compiler built-in */
};
}
/// 打印到标准输出。
///
/// 等效于 [`println!`] 宏,只是在消息末尾不打印换行符。
///
/// 注意,默认情况下,stdout 通常是行缓冲的,因此可能有必要使用 [`io::stdout().flush()`][flush] 以确保立即发出输出。
///
///
/// `print!` 宏将锁定每个调用的标准输出。如果您在热循环内调用 `print!`,则此行为可能是循环的瓶颈。
/// 为了避免这种情况,用 [`io::stdout().lock()`][lock] 锁定 stdout:
///
/// ```
/// use std::io::{stdout, Write};
///
/// let mut lock = stdout().lock();
/// write!(lock, "hello world").unwrap();
/// ```
///
/// `print!` 仅用于程序的主要输出。请改用 [`eprint!`] 打印错误和进度消息。
///
/// [flush]: crate::io::Write::flush
/// [`println!`]: crate::println
/// [`eprint!`]: crate::eprint
/// [lock]: crate::io::Stdout
///
/// # Panics
///
/// 如果写入 `io::stdout()` 失败,就会出现 panics。
///
/// 写入非阻塞 stdout 可能会导致错误,这将导致此宏 panic。
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// print!("this ");
/// print!("will ");
/// print!("be ");
/// print!("on ");
/// print!("the ");
/// print!("same ");
/// print!("line ");
///
/// io::stdout().flush().unwrap();
///
/// print!("this string has a newline, why not choose println! instead?\n");
///
/// io::stdout().flush().unwrap();
/// ```
///
///
///
///
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
#[allow_internal_unstable(print_internals)]
macro_rules! print {
($($arg:tt)*) => {{
$crate::io::_print($crate::format_args!($($arg)*));
}};
}
/// 使用换行符打印到标准输出。
///
/// 在所有平台上,新行是一个换行符 (也就是 `\n`/`U+000A`),并不包含回车符 (也就是 `\r`/`U+000D`)。
///
///
/// 此宏使用与 [`format!`] 相同的语法,但改为写入标准输出。
/// 有关详细信息,请参见 [`std::fmt`]。
///
/// `println!` 宏将锁定每个调用的标准输出。
/// 如果您在热循环内调用 `println!`,则此行为可能是循环的瓶颈。
/// 为了避免这种情况,用 [`io::stdout().lock()`][lock] 锁定 stdout:
///
/// ```
/// use std::io::{stdout, Write};
///
/// let mut lock = stdout().lock();
/// writeln!(lock, "hello world").unwrap();
/// ```
///
/// `println!` 仅用于程序的主要输出。请改用 [`eprintln!`] 打印错误和进度消息。
///
/// [`std::fmt`]: crate::fmt
/// [`eprintln!`]: crate::eprintln
/// [lock]: crate::io::Stdout
///
/// # Panics
///
/// 如果写入 [`io::stdout`] 失败,就会出现 panics。
///
/// 写入非阻塞 stdout 可能会导致错误,这将导致此宏 panic。
///
/// [`io::stdout`]: crate::io::stdout
///
/// # Examples
///
/// ```
/// println!(); // 只打印换行符
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// let local_variable = "some";
/// println!("format {local_variable} arguments");
/// ```
///
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
() => {
$crate::print!("\n")
};
($($arg:tt)*) => {{
$crate::io::_print($crate::format_args_nl!($($arg)*));
}};
}
/// 打印到标准错误。
///
/// 等效于 [`print!`] 宏,除了输出转到 [`io::stderr`] 而不是 [`io::stdout`]。
///
/// 有关用法示例,请参见 [`print!`]。
///
/// 仅将 `eprint!` 用于错误和进度消息。
/// 改用 `print!` 作为程序的主要输出。
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
/// # Panics
///
/// 如果写入 `io::stderr` 失败,就会出现 panics。
///
/// 写入非阻塞 stdout 可能会导致错误,这将导致此宏 panic。
///
/// # Examples
///
/// ```
/// eprint!("Error: Could not complete task");
/// ```
///
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
#[allow_internal_unstable(print_internals)]
macro_rules! eprint {
($($arg:tt)*) => {{
$crate::io::_eprint($crate::format_args!($($arg)*));
}};
}
/// 使用换行符打印到标准错误。
///
/// 等效于 [`println!`] 宏,除了输出转到 [`io::stderr`] 而不是 [`io::stdout`]。
///
/// 有关用法示例,请参见 [`println!`]。
///
/// 仅将 `eprintln!` 用于错误和进度消息。
/// 改用 `println!` 作为程序的主要输出。
///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
/// [`println!`]: crate::println
///
/// # Panics
///
/// 如果写入 `io::stderr` 失败,就会出现 panics。
///
/// 写入非阻塞 stdout 可能会导致错误,这将导致此宏 panic。
///
/// # Examples
///
/// ```
/// eprintln!("Error: Could not complete task");
/// ```
///
#[macro_export]
#[stable(feature = "eprint", since = "1.19.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! eprintln {
() => {
$crate::eprint!("\n")
};
($($arg:tt)*) => {{
$crate::io::_eprint($crate::format_args_nl!($($arg)*));
}};
}
/// 打印并返回给定表达式的值,以进行快速而肮脏的调试。
///
/// 一个例子:
///
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// // ^-- 打印: [src/main.rs:2] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
/// 宏通过使用给定表达式的类型的 `Debug` 实现将值与宏调用的源位置以及表达式的源代码一起打印到 [标准错误][stderr] 来工作。
///
///
/// 调用表达式上的宏会移动并获取它的所有权,然后再返回不变的求值表达式。
/// 如果表达式的类型未实现 `Copy`,并且您不想放弃所有权,则可以改用 `dbg!(&expr)` 借用某些表达式 `expr`。
///
/// `dbg!` 宏在发行版中的工作原理完全相同。
/// 当仅在发行版本中发生的调试问题或在发行模式下进行的调试明显更快时,此功能很有用。
///
/// 请注意,宏的目的是作为调试工具,因此您应该避免在版本控制中长时间使用它 (测试和类似的情况除外)。
/// 使用其他工具 (例如 [`log`] crate 的 [`debug!`] 宏) 可以更好地完成生产代码的调试输出。
///
/// # Stability
///
/// 不应依赖此宏打印的确切输出,并且可能会受到 future 的更改。
///
/// # Panics
///
/// 如果写入 `io::stderr` 失败,就会出现 panics。
///
/// # 进一步的例子
///
/// 用一种方法:
///
/// ```rust
/// fn foo(n: usize) {
/// if let Some(_) = dbg!(n.checked_sub(4)) {
/// // ...
/// }
/// }
///
/// foo(3)
/// ```
///
/// 打印到 [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// ```
///
/// 单纯的析因实现:
///
/// ```rust
/// fn factorial(n: u32) -> u32 {
/// if dbg!(n <= 1) {
/// dbg!(1)
/// } else {
/// dbg!(n * factorial(n - 1))
/// }
/// }
///
/// dbg!(factorial(4));
/// ```
///
/// 打印到 [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// ```
///
/// `dbg!(..)` 宏移动输入:
///
/// ```compile_fail
/// /// `usize` 的包装器,重要的是它不可复制。
/// #[derive(Debug)]
/// struct NoCopy(usize);
///
/// let a = NoCopy(42);
/// let _ = dbg!(a); // <-- `a` 被移到了这里。
/// let _ = dbg!(a); // <-- `a` 被再次移动; error!
/// ```
///
/// 您也可以使用不带任何值的 `dbg!()` 来仅在到达文件和行时打印它。
///
/// 最后,如果要 `dbg!(..)` 多个值,它将把它们视为一个元组 (并返回它) :
///
/// ```
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
/// ```
///
/// 但是,遵循在宏调用中忽略尾部逗号的约定,带有尾部逗号的单个参数仍不会被视为元组。如果需要一个,可以直接使用一个 1 元组:
///
/// ```
/// assert_eq!(1, dbg!(1u32,)); // 尾部逗号被忽略
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
/// ```
///
/// [stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr)
/// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
/// [`log`]: https://crates.io/crates/log
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
#[macro_export]
#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")]
#[stable(feature = "dbg_macro", since = "1.32.0")]
macro_rules! dbg {
// NOTE: 我们不能使用 `concat!` 作为 `eprintln!` 的格式参数来生成静态字符串,因为 `file!` 可能包含 `{` 或 `$val` 表达式可能是一个块 (`{。
// }`),在这种情况下 `eprintln!` 的格式将不正确。
//
//
() => {
$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!())
};
($val:expr $(,)?) => {
// 在此使用 `match` 是有意的,因为它会影响临时人员的生命周期 - https://stackoverflow.com/a/48732525/1063961
//
match $val {
tmp => {
$crate::eprintln!("[{}:{}] {} = {:#?}",
$crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($($crate::dbg!($val)),+,)
};
}
#[cfg(test)]
macro_rules! assert_approx_eq {
($a:expr, $b:expr) => {{
let (a, b) = (&$a, &$b);
assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
}};
}