uprintln!
在下一个练习中,我们将实现uprint!
系列宏。您的目标是使这行代码正常工作:
#![allow(unused)] fn main() { uprintln!(serial, "The answer is {}", 40 + 2); }
它必须通过串行接口发送字符串"The answer is 42"
。
我们该怎么做?研究println!
的std
实现很有帮助。
#![allow(unused)] fn main() { // src/libstd/macros.rs macro_rules! print { ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); } }
到目前为止看起来很简单。我们需要内置的format_args!
宏 (它是在编译器中实现的,所以我们看不到它的实际功能)。
我们必须以完全相同的方式使用该宏。此_print
函数的作用是什么?
#![allow(unused)] fn main() { // src/libstd/io/stdio.rs pub fn _print(args: fmt::Arguments) { let result = match LOCAL_STDOUT.state() { LocalKeyState::Uninitialized | LocalKeyState::Destroyed => stdout().write_fmt(args), LocalKeyState::Valid => { LOCAL_STDOUT.with(|s| { if s.borrow_state() == BorrowState::Unused { if let Some(w) = s.borrow_mut().as_mut() { return w.write_fmt(args); } } stdout().write_fmt(args) }) } }; if let Err(e) = result { panic!("failed printing to stdout: {}", e); } } }
这看起来很复杂,但我们唯一感兴趣的部分是:w.write_fmt(args)
和stdout().write_fmt(args)
。
什么print!
最终要做的是使用format_args!
的输出调用fmt::Write::write_fmt
方法!
幸运的是,我们也不必实现fmt::Write::write_fmt
方法,因为它是默认方法。我们只需要实现fmt::Write::write_str
方法。
让我们这样做吧。
这就是相等的macro的一面。剩下的工作是提供write_str
方法的实现。
上面我们看到Write
在std::fmt
中。 我们无法访问std
,但Write
也可以在core::fmt
中使用。
#![deny(unsafe_code)] #![no_main] #![no_std] use core::fmt::{self, Write}; #[allow(unused_imports)] use aux11::{entry, iprint, iprintln, usart1}; macro_rules! uprint { ($serial:expr, $($arg:tt)*) => { $serial.write_fmt(format_args!($($arg)*)).ok() }; } macro_rules! uprintln { ($serial:expr, $fmt:expr) => { uprint!($serial, concat!($fmt, "\n")) }; ($serial:expr, $fmt:expr, $($arg:tt)*) => { uprint!($serial, concat!($fmt, "\n"), $($arg)*) }; } struct SerialPort { usart1: &'static mut usart1::RegisterBlock, } impl fmt::Write for SerialPort { fn write_str(&mut self, s: &str) -> fmt::Result { // TODO implement this // hint: this will look very similar to the previous program Ok(()) } } #[entry] fn main() -> ! { let (usart1, _mono_timer, _itm) = aux11::init(); let mut serial = SerialPort { usart1 }; uprintln!(serial, "The answer is {}", 40 + 2); loop {} }