【问题标题】:Why does fmt::Arguments as_str not work when arguments are passed?为什么 fmt::Arguments as_str 在传递参数时不起作用?
【发布时间】:2021-03-27 18:20:21
【问题描述】:

我正在使用no_std 为我的操作系统制作一个VGA 打印宏,但由于某种原因无法正常工作。我正在使用vga crate,这样我就不必自己完成所有的 VGA 代码。我有一个名为_print的函数:

use core::fmt::{Arguments, Write};
use vga::colors::Color16;
use vga::writers::{Graphics640x480x16, GraphicsWriter};

pub fn _print(args: Arguments) {
    unsafe {
        let mut i: usize = 0;
        for (_offset, character) in args.as_str().unwrap().chars().enumerate() {
            Mode.draw_character(CurrentTextX + i, CurrentTextY, character, CurrentTextColor);
            i += 8;
        }
    }
}

然后我有一个名为vprint!的宏:

#[macro_export]
macro_rules! vprint {
    ($($arg:tt)*) => {
        crate::videographicsarray::_print(format_args!($($arg)*));
    };
}

我没有使用alloc。我已经看到与此工作完全一样的代码,但由于某种原因,我的代码无法正常工作。它显示我输入的文本,但如果我传递任何参数,它就会恐慌。我做错了什么?

【问题讨论】:

  • “它不显示我传递的任何参数”是什么意思?它只是什么都不做,它会恐慌还是?
  • 它很恐慌,抱歉没有说明。

标签: rust arguments


【解决方案1】:

您的代码会出现混乱,因为 as_str() 仅在没有参数的情况下返回 Some。因此,当您立即 unwrap() 它会恐慌,例如您有要格式化的参数。

如果没有要格式化的参数,则获取格式化的字符串。

这可以用来避免在最琐碎的情况下进行分配。

——std::fmt::Arguments::as_str() docs

相反,您可以使用args.to_string() 而不是args.as_str().unwrap(),将其格式化为String。所以不管有没有参数,它实际上都是格式化的。

pub fn _print(args: Arguments) {
    unsafe {
        let mut i: usize = 0;
        for (_offset, character) in args.to_string().chars().enumerate() {
            Mode.draw_character(CurrentTextX + i, CurrentTextY, character, CurrentTextColor);
            i += 8;
        }
    }
}

如果你想避免不必要的分配,那么你可以使用unwrap_or_else(),并且只有在as_str()返回None时才使用to_string()。在包装Cow 时,避免将&str 转换为String

use std::borrow::Cow;

let formatted_str = args
    .as_str()
    .map(Cow::Borrowed)
    .unwrap_or_else(|| Cow::Owned(args.to_string()));

no_std

因为您使用的是 no_std 而不是 alloc 板条箱。然后你可以定义一个u8 缓冲区来格式化。例如。使用let buf = [u8; N];,其中N 为格式化字符串提供了足够的空间。

之后,您可以围绕 &mut [u8] 缓冲区实现自己的包装器,该缓冲区实现 core::fmt::Write 特征。您可以将该包装器与core::fmt::write() 一起使用。

您可以使用此答案中的struct WriteTo,而不是自己实现:How can I use the format! macro in a no_std environment?

pub fn _print(args: Arguments) {
    let mut buf = [0u8; 64];
    let formatted_str: &str = write_to::show(&mut buf, args).unwrap();

    unsafe {
        let mut i: usize = 0;
        for (_offset, _character) in formatted_str.chars().enumerate() {
            Mode.draw_character(CurrentTextX + i, CurrentTextY, character, CurrentTextColor);

            i += 8;
        }
    }
}

【讨论】:

  • 它给出了一个错误:'在当前范围内没有为结构Arguments<'_>找到名为to_string的方法'
  • @DuelTheBearded 等等,你在用no_std吗? alloc 呢?
  • 我正在使用no_std,是的。
  • @DuelTheBearded 您能否更新问题,包括您的no_std“设置”。就像您正在使用的板条箱一样,例如corealloc?
  • @DuelTheBearded 没有完全说清楚。我需要知道您是否使用alloc。如果没有,那么您需要使用其他东西来写入,然后使用例如core::fmt::write(&mut writer, args)。总而言之,as_str() 不起作用,因为如果没有要格式化的参数,它只会返回 Some
猜你喜欢
  • 2012-03-27
  • 1970-01-01
  • 2021-05-29
  • 2015-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多