[英]How can I simplify repeating function logic
I'm wondering if there is a way to improve the current structure of some functions in my program since I feel there is a fair amount of unwanted repetition happening.我想知道是否有办法改进程序中某些函数的当前结构,因为我觉得发生了大量不需要的重复。
I'm writing a tiny logger so CLI applications can have prettier text in the terminal.我正在编写一个小型记录器,以便 CLI 应用程序可以在终端中显示更漂亮的文本。 I have a couple functions that add some icons to what is going to stdout such as
success()
, it takes a message and adds a green checkmark icon to it, same with error()
, warn()
etc. They can all either add a newline character at the end or ignore it depending on if the user called same()
before it.我有几个函数可以向标准输出添加一些图标,例如
success()
,它需要一条消息并向其添加一个绿色复选标记图标,与error()
、 warn()
等相同。它们都可以添加最后一个换行符或忽略它,取决于用户是否在它之前调用了same()
。
Currently they use the three functions defined below to decide whether or not to add a newline, and whether or not to add a timestamp.目前他们使用下面定义的三个函数来决定是否添加换行符,以及是否添加时间戳。
/// Outputs to stdout with an icon
fn output<T: Display>(&mut self, message: T, icon: LogIcon) {
let timestamp = self.timestamp();
if self.same_line {
print!("{} {}{}", icon, timestamp, message);
} else {
println!("{} {}{}", icon, timestamp, message);
}
self.same_line = false;
}
/// Outputs to stderr with an icon
fn output_error<T: Display>(&mut self, message: T, icon: LogIcon) {
let timestamp = self.timestamp();
if self.same_line {
eprint!("{} {}{}", icon, timestamp, message);
} else {
eprintln!("{} {}{}", icon, timestamp, message);
}
self.same_line = false;
}
/// Outputs to stdout normally
fn output_normal<T: Display>(&mut self, message: T) {
let timestamp = self.timestamp();
if self.same_line {
print!("{}{}", timestamp, message);
} else {
println!("{}{}", timestamp, message);
}
self.same_line = false;
}
This is how the success
function makes use of output function at the moment:这是
success
函数目前如何使用输出函数的方式:
pub fn success<T: Display>(&mut self, message: T) {
self.output(message, LogIcon::CheckMark);
}
The same applies for all other functions, they either output to stderr
or stdout
.这同样适用于所有其他函数,它们输出到
stderr
或stdout
。
You could change same_line
into line_ending
.您可以将
same_line
更改为line_ending
。 Instead of storing true, you would store \\n
and always use print!("... {}", ..., &self.line_ending)
.而不是存储真,你会存储
\\n
并始终使用print!("... {}", ..., &self.line_ending)
。 I would also add a function pop_line_ending()
which returns the stored line ending and clears it.我还将添加一个函数
pop_line_ending()
,它返回存储的行结尾并清除它。
You can make a function that is generic over implementations of std::io::Writer
, and also accepts std::fmt::Arguments
, which is the formatting arguments applied at compile time to the input string in a way that can be conveniently passed around.您可以创建一个在
std::io::Writer
实现上通用的函数,并且还接受std::fmt::Arguments
,这是在编译时以一种可以方便的方式应用于输入字符串的格式化参数路过。
use std::{fmt, fmt::Display, io};
fn write_output<W: io::Write>(&mut self, args: fmt::Arguments, newline: bool, mut writer: W) {
write!(writer, "{}", args).unwrap();
if newline {
write!(writer, "\n").unwrap();
}
writer.flush().unwrap();
}
Then pass either stdout()
or stderr()
as required in each call, along with the other arguments:然后在每次调用中根据需要传递
stdout()
或stderr()
以及其他参数:
fn output<T: Display>(&mut self, message: T, icon: LogIcon) {
let timestamp = self.timestamp();
self.write_output(
format_args!("{} {}{}", icon, timestamp, message),
!self.same_line,
io::stdout(),
);
self.same_line = false;
}
fn output_error<T: Display>(&mut self, message: T, icon: LogIcon) {
let timestamp = self.timestamp();
self.write_output(
format_args!("{} {}{}", icon, timestamp, message),
!self.same_line,
io::stderr(),
);
self.same_line = false;
}
fn output_normal<T: Display>(&mut self, message: T) {
let timestamp = self.timestamp();
self.write_output(
format_args!("{}{}", timestamp, message),
!self.same_line,
io::stdout(),
);
self.same_line = false;
}
I like Peter Hall's solution, but I think it can be simplified.我喜欢 Peter Hall 的解决方案,但我认为它可以简化。 I got rid of the
fmt::Arguments
argument and passed in the message and optional icon.我去掉了
fmt::Arguments
参数并传入了消息和可选图标。 Also got rid of the newline
argument and used the member variable directly.也去掉了
newline
参数,直接使用了成员变量。
use std::{fmt, fmt::Display, io};
struct LogIcon {}
impl Display for LogIcon {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "[ICON]")
}
}
struct Logger {
same_line: bool,
}
impl Logger {
fn write_output<T: Display, W: io::Write>(
&mut self,
message: T,
icon: Option<LogIcon>,
mut writer: W,
) {
if let Some(icon) = icon {
write!(writer, "{} ", icon);
}
write!(writer, "{}{}", self.timestamp(), message);
if self.same_line {
write!(writer, "\n").unwrap();
}
writer.flush().unwrap();
self.same_line = false;
}
fn output<T: Display>(&mut self, message: T, icon: LogIcon) {
self.write_output(message, Some(icon), io::stdout());
}
fn output_error<T: Display>(&mut self, message: T, icon: LogIcon) {
self.write_output(message, Some(icon), io::stderr());
}
fn output_normal<T: Display>(&mut self, message: T) {
self.write_output(message, None, io::stdout())
}
fn timestamp(&self) -> &'static str {
"A TIMESTAMP"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.