rust 使用第三方库构建mini命令行工具

news2024/12/27 17:46:46

这是上一篇 rust 学习 - 构建 mini 命令行工具的续作,扩展增加一些 crate 库。这些基础库在以后的编程工作中会常用到,他们作为基架存在于项目中,解决项目中的某个问题。

项目示例还是以上一篇的工程为基础做调整修改ifun-grep 仓库地址

怎么去使用已发布的 crate 库

在开发ifun-grep项目时,运行项目命令为cargo run -- hboot hello.txt,测试项目的逻辑正确。在发布到crates.io要如何使用呢,

在项目中使用

作为项目的一个功能函数,逻辑事务调用。在crates.io 中找到需要的库

安装已经发布的示例库ifun-grep . 通过cargo add添加依赖项

这里我们有一个测试示例项目rust-web,这是在另一篇rust 基础中创建的示例项目。

$> cargo add ifun-grep

安装成功后,可以在在项目的Cargo.toml看到依赖

[dependencies]
ifun-grep = "0.1.0"

main.rs导入库使用,这个库包括了一个结构体Config,三个方法find\find_insensitive\run

use ifun_grep;

fn main(){
    let search = String::from("let");
    let config = ifun_grep::Config {
        search,
        file_path: String::from("hello.txt"),
        ignore_case: true,
    };

    let result = ifun_grep::run(config);

    println!("{}", result.is_ok());
}

执行cargo run,可以看到输出了false。因为文件hello.txt不存在,在上一篇文中我们把错误处理统一放到了main.rs文件中处理的。而我们这边作为一个 lib 库,直接调用的run函数,所以这边没有任何的错误输出,只提示我们没有执行成功。

我们可以在项目目录下新建一个测试文件hello.txt

Let life be beautiful like summer flowers.

The world has kissed my soul with its pain.

Eyes are raining for her.

you also miss the stars.

再次运行,可以看到打印的输出内容。Let life be beautiful like summer flowers.

可以通过cargo remove ifun-grepCargo.toml移除依赖

作为脚本命令执行

可以看到作为功能性函数调用时,只能手动去初始化函数调用。不能像执行命令一样,传递参数调用,也就不能执行main.rs中的处理逻辑以及错误打印。

通过cargo install 安装二进制可执行文件的库

$> cargo install ifun-grep

安装完成后,就可以在全局环境中使用命令ifun-grep了。

通过cargo uninstall ifun-grep 移除。

开发时如何测试使用

开发时只能cargo run去执行main.rs文件,不能直接使用ifun-grep命令

可以通过cargo build 构建编译,在target/debug下生成二进制文件

ifun-grep-build.jpg

这样可以通过相对目录地址访问可执行文件执行命令

$> target/debug/ifun-grep Let hello.txt

如果我们的代码 存储在 github 或者 gitee 上,就可以将编译包压缩发布版本,这样需要的人不需要 cargo 就可以下载安装。

构建发布版本

$> cargo build --release

我的代码仓库在 giteeifun-grep 基础版本发布

ifun-grep-release v0.1.0.png

下载压缩包后,需要把可执行文件配置到系统环境中,全局可用。也可以不用配置,直接使用文件路径地址执行命令。

还需要考虑一个问题,就是系统的兼容性,mac、windows、linux 等等,想要发布一个兼容的库,可能还需要针对性构建编译包并发布

这里演示的是 mac 系统下载发布包后,通过路径访问执行命令

ifun-grep-release v0.1.0 -run.png

clap库解析 cli 参数

clap库包含了对子命令、shell 完成和更好的帮助信息。

安装,参数--features表示启动特定功能,

$> cargo add clap --features derive

clap除了提供基础的功能之外,还可以通过--features开启特定功能。derive启动自定义派生功能,可以通过过程宏处理参数。

src/main.rs 中使用

// use std::{env, process};
use clap::Parser;
use ifun_grep::{Config};

fn main() {
    // let args: Vec<String> = env::args().collect();

    let config = Config::parse();

    // let config = Config::build(&args).unwrap_or_else(|err| {
    //     // println!("error occurred parseing args:{err}");
    //     eprintln!("error occurred parseing args:{err}");
    //     process::exit(1);
    // });
}

结构体 Config 派生了一个内部函数parse,可以直接解析参数生成实例 config

还需要修改src/lib.rs,使得结构体 Config 用拥有这种能力

use clap::Parser;

#[derive(Parser, Debug)]
pub struct Config {
    #[arg(long)]
    pub search: String,
    #[arg(long)]
    pub file_path: String,
    #[arg(long)]
    pub ignore_case: bool,
}

首先不再使用std::env去解析 cli 参数,也不需要调用Config的 build 方法去实例化创建 config。

通过clap::Parser的过程式宏 Parser 去解析 cli 参数,并返回结构体Config的实例 config

执行命令

$> cargo run

报错了,如图,首先这个错误信息很友好,告诉我们必填的参数信息

clap-run.png

增加参数配置,调用命令执行

$> cargo run --  --search Let --file-path hello.txt

可以看到结果成功了,对比之前调用方式cargo run -- Let hello.txt,多了一个参数名称定义--search

#[arg(long)] 参数宏是用来定义参数接受的标志,arg还有许多其他的功能

移除掉#[arg(long)],执行命令 cargo run

use clap::Parser;

#[derive(Parser, Debug)]
pub struct Config {
    pub search: String,
    pub file_path: String,
    pub ignore_case: bool,
}

报错了,thread 'main' panicked at 'Argument 'ignore_case is positional, it must take a value,意思是 ignore_case 必须要有一个值,ignore_case是一个布尔值,隐式启动了#[arg(action = ArgAction::SetTrue)],所以需要设置接受标志

布尔值只需要通过设置标志,而不需要设置值,--ignore_case 就表示 true

use clap::Parser;

pub struct Config {
    pub search: String,
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
}

再次执行命令cargo run,

clap-run-noArg.png

还需要必填的两个参数,此时不需要--

$> cargo run --  Let hello.txt

要想开启大小写不敏感,则需要增加--ignore-case

$> cargo run --  let hello.txt --ignore-case

需要注意的是结构体定义的下划线ignore_case,在 clap 接受参数的标志为--ignore-case

增加命令的描述信息

通常 cli 的命令都有一个--help功能,这可以基本说明这个脚本是干嘛的,以及怎么去使用

而这些 clap 正好有。测试一下,代码修改后需执行cargo build

$> target/debug/ifun-grep --help

ifun-grep-help.png

可以看到对于ifun-grep一个基本的使用方式,包括Usage、Arguments、Options。还展示了对于结构体Config的注释说明、例子。
通过简写的-h可以让描述更加紧凑一点。

clap 通过#[command()]可以从Cargo.toml获取到一些基础信息,生成 Command 实例

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Config {
    pub search: String,
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
}

编译后,执行--help

ifun-grep-clap-command.png

也可以自定义这些字段的值。

#[derive(Parser)]
#[command(name = "ifun-grep")]
#[command(author = "hboot <bobolity@163.com>")]
#[command(version = "0.2.0")]
#[command(about="A simple fake grep",long_about=None)]
pub struct Config {
    pub search: String,
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
}

通过执行ifun-grep -V可以查看设置的name、version信息

定义参数非必须

通过Option定义字段数据类型,使得这个字段非必须

#[derive(Parser)]
pub struct Config {
    name: Option<String>,
}

通过--help查看参数是,必须的Arguments:参数是<SEARCH>使用尖括号的;而非必须的是中括号[name].

如果某个参数可以接受多个,则通过集合定义类型

#[derive(Parser)]
pub struct Config {
    name: Vec<String>,
}

在命令执行多余的参数会解析到字段 name 中。隐式的启动了#[arg(action = ArgAction::Set)],处理多个值。

使用标志命名参数

在之前的实例中,已经使用了#[arg(short, long)],它用来标识参数名称,它可以:

  • 意图表达更明确
  • 不用在意参数的顺序
  • 使参数变的可选
#[derive(Parser)]
pub struct Config {
    #[arg(short, long)]
    pub search: String,
    #[arg(short, long)]
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
}

可以通过--help查看变化,所有的参数都变成了Options

ifun-grep-arg.png

子命令

在执行ifun-grep时,携带子命令执行。通过#[derive(Subcommand)]标志属性,子命令也可以有自己的版本、作者信息、参数等等

use clap::{Args, Parser, Subcommand};

#[derive(Parser)]
pub struct Config {
    #[arg(short, long)]
    pub search: String,
    #[arg(short, long)]
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    Add(AddArgs),
}

#[derive(Args)]
pub struct AddArgs {
    name: Option<String>,
}

默认值

可以通过#[arg(default_value_t)]定义默认值,定义字段file_path默认值

#[derive(Parser)]
pub struct Config {
    #[arg(short, long)]
    pub search: String,
    #[arg(short, long, default_value = "hello.txt")]
    pub file_path: String,
    #[arg(short, long)]
    pub ignore_case: bool,
}

调用命令执行时,可以不在设置该字段

$> target/debug/ifun-grep -s Let

命令执行是查询成功的.

其他的功能比如:数据校验、自定义值解析逻辑、自定义校验等等。

anyhow 处理错误

提供了一种错误类型anyhow::Error. 处理出现的错误。

之前处理文件读取的逻辑,使用了?

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let content = fs::read_to_string(config.file_path)?;

    Ok(())
}

当文件不存在时,会打印出错误信息something error:No such file or directory (os error 2).但不知道具体哪个文件不存在。

可以通过自定义错误类型IfunError,来构建自己的错误信息

#[derive(Debug)]
pub struct IfunError(String);

pub fn run(config: Config) -> Result<(), IfunError> {
    let file_path = config.file_path.clone();
    let content = fs::read_to_string(config.file_path)
        .map_err(|err| IfunError(format!("could not read file {} - {}", file_path, err)))?;

    // ...
    Ok(())
}

再次执行访问不存在的文件,报错信息为something error:IfunError("could not read file 1.txt - No such file or directory (os error 2)")

anyhow正好做了事情,可以通过 anyhow 的特征context可以附加错误内容信息,也保留了原始错误。

安装 crate anyhow

$> cargo add anyhow

调整处理读取文件的函数run,在src/lib.rs文件中修改:

use anyhow::{Context, Result};

pub fn run(config: Config) -> Result<()> {
    let file_path = config.file_path.clone();
    let content = fs::read_to_string(config.file_path)
        .with_context(|| format!("could not read file {}", file_path))?;

    // ...
    Ok(())
}

还需要修改src/main.rs文件,将错误输出方式改为{:?}

fn main() {
    // ...
    if let Err(e) = run(config) {
        // println!("something error:{e}");
        eprintln!("something error:{:?}", e);
        process::exit(1);
    }
}

再次执行命令,可以看到错误更加的友好。

ifun-grep-anyhow.png

使用anyhow!()宏,输出错误信息

src/main.rs,读取文件之前增加错误输出

fn main(){
    // ...
    println!("{}", anyhow!("anyhow error {}", "running"));
    //...
}

使用bail!()宏,中断执行

调用执行返回错误,中断程序执行

src/main.rs,读取文件之前增加错误输出

use anyhow::{anyhow, bail};

fn main() -> Result<(), anyhow::Error> {
    // ...
    println!("{}", anyhow!("anyhow error {}", "running"));

    bail!("permission denied for accessing {}", config.file_path)
    //...
}

调用bail!时,返回值必须是Result<(), anyhow::Error>类型

bail!同等于return Err(anyhow!())

跟踪错误栈

打印出错误信息,我们可以知道发生了错误,想知道是哪个文件、那行代码发生的错误,则需要开启错误栈追踪。

这是一个特性功能,需要指定特性启用

$> cargo add anyhow --features backtrace

然后通过设置环境变量,

  • RUST_BACKTRACE=1 panics和 error 都有错误栈输出
  • RUST_LIB_BACKTRACE=1 仅打开错误输出
  • RUST_BACKTRACE=1RUST_LIB_BACKTRACE=0 仅 panic 时

在执行命令时,设置环境变量,打开错误输出时的错误追踪

$> RUST_LIB_BACKTRACE=1 cargo run -- -s let -f 1.txt

thiserror 自定义自己的错误类型

anyhow不同,thiserror可以用来自定义错误类型。

通过过程式宏#[derive(Error)],它是由 std::error::Error派生而来。

$> cargo add thiserror

定义一个文件不能存在的错误类型,并用于读取文件时的逻辑

use thiserror::Error;

#[derive(Error, Debug)]
pub enum IfunError {
    #[error("the file is't exist")]
    FileNotExist(#[from] std::io::Error),
}

pub fn run(config: Config) -> Result<(), IfunError> {
    let content = fs::read_to_string(config.file_path)?;

    // ...

    Ok(())
}

执行命令,访问不存在的文件。错误信息输出会被自定义的类型包裹:

ifun-grep-thiserror.png

ansi_term 更好的打印输出

ansi_term控制台上的打印输出,包括字体样式、格式化。

安装

$> cargo add ansi_term

包括对文本的字体颜色、背景色、是否加粗、是否闪烁等等。

通过ansi_term::Colour控制字体样式

我们将ifun-grep的 参数打印使用颜色标记输出

use ansi_term::Colour::{Green, Yellow};

fn main(){
    //...
    println!(
        "will search {} in {}",
        Green.paint(&config.search),
        Yellow.paint(&config.file_path)
    );
}

执行命令cargo run -- -s Let -f hello.txt

ifugn-grep-ansi_term.png

加粗bold()、加下划线underline()、背景色on()

use ansi_term::Colour::{Green, Yellow};

fn main(){
    //...
    println!(
        "will search {} in {}",
        Green.bold().paint(&config.search),
        Yellow.underline().paint(&config.file_path)
    );
}

给程序查询出的行数据加背景色、闪烁

use ansi_term::Colour::{Red, Yellow};

pub fn run(config: Config) -> Result<(), anyhow::Error> {
    //...
    for line in result {
        println!("{}", Red.on(Yellow).blink().paint(line));
    }

    Ok(())
}

通过ansi_term::Style控制样式

Colour是一个枚举类型,专门针对颜色样式处理;Style是结构体类型,是字体样式的集合。

设置字体颜色,结构体需要实例化一个实例对象,然后再调用对应的方法。

use ansi_term::Colour::{Green, Yellow};
use ansi_term::Style;

fn main(){
    //...

    println!(
        "will search {} in {}",
        Green.bold().paint(&config.search),
        // Yellow.underline().paint(&config.file_path)
        Style::new().fg(Yellow).paint(&config.file_path)
    );
}

颜色扩展ansi_term::Colour::Fixed

除了内置枚举的颜色,还可以通过色码值设置颜色。0-255

use ansi_term::Colour::Fixed;

Fixed(154).paint("other color");

也可以通过ansi_term::Colour::RGB,设置三个不同的值

use ansi_term::Colour::RGB;

RGB(154, 56, 178).paint("other color");

此外还有内置ANSIStrings类型,可以通过to_string()方法转换为String;

支持格式化输出\[u8]字节字符串,对于不知道编码的文本输出很有用。会生成ANSIByteString类型,通过write_to方法写入输出流中。

Green.paint("ansi_term".as_bytes()).write_to(&mut std::io::stdout()).unwrap();

indicatif展示进度条

处理任务时,显示任务的执行进度。会让人感觉良好,更有耐心等待执行完毕

$> cargo add indicatif

手动创建一个进度条,为了看到进度条的进度效果,可以使用std::thred线程休眠一段时间。

use indicatif::ProgressBar;
use std::{thread, time};

fn main(){
    let bar = ProgressBar::new(100);
    let ten_millis = time::Duration::from_millis(10);
    for _ in 0..100 {
        bar.inc(1);
        thread::sleep(ten_millis);
        // ...
    }

    bar.finish();
}

通过ProgressBar类型创建了一个进度条的实例对象,然后通过实例bar.inc()逐步增加进度。完成后调用bar.finish()表示进度完成,并保留显示进度信息。

ifun-grep-indicatif.jpg

也支持多进度条的MultiProgress

log日志记录

一个程序运行时期的日志打印,非常重要,这对于运行监测喝解决有问题都有很到的帮助。

$> cargo add log

通常可以将日志按照登记划分,比如错误、警告、信息等。还需要一个日志输出的适配器 env_logger,可以将日志写入终端、日志服务器等。

$> cargo add env_logger

美化输出,将接受到的参数作为信息info!()输出,将产生的错误使用error!()输出

env_logger默认输出日志到终端,

use log;

fn main() {
    env_logger::init();

    // ...
    log::info!(
        "will search {} in {}",
        Green.bold().paint(&config.search),
        Style::new().fg(Yellow).paint(&config.file_path)
    );

    // ...

    if let Err(e) = run(config) {
        log::error!("something error:{:?}", e);
        process::exit(1);
    }

}

必须在程序之前初始化完毕日志环境变量配置。默认只展示error错误类型的日志

执行cargo run -- -s Let -f 1.txt命令访问不存在的文件,可以看到只有 error 错误输出打印。

通过设置变量RUST_LOG=info,查看

$> RUST_LOG=info cargo run -- -s Let -f 1.txt

ifun-grep-log.png

初始化指定信息类型

在执行命令前加上RUST_LOG=info很麻烦,有遗忘的可能,可以通过初始化env_logger::init()调用时,设定一个默认值

use env_logger::Env;

fn mian(){
    env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();

    // ...
}

通过终端设置的变量优先级比默认值高,可以通过执行时设置变量覆盖默认值。

自定义输出模板

可以看到默认的输出打印包括了时间、类型以及模块名。可以通过改变模板自定义输出格式

use std::io::Write;

fn main(){
    env_logger::builder()
        .format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args()))
        .init();
}

输出格式改变为信息类型 - 信息。使用默认的挺好,现在好多编辑器的日志输出都是这种格式。

测试

之前的单元测试示例都是和逻辑代码放在一起的,并用#[test]注释。可以将这些测试放在tests目录中

新建tests/lib.rs用于存放单元测试用例。

use ifun_grep::{find, find_insensitive};

#[test]
fn case_sensitive() {
    let search = "rust";
    let content = "\
nice. rust
I'm hboot.
hello world.
Rust
";

    assert_eq!(vec!["nice. rust"], find(search, content));
}

#[test]
fn case_insensitive() {
    let search = "rust";
    let content = "\
nice. rust
I'm hboot.
hello world.
Rust
";

    assert_eq!(
        vec!["nice. rust", "Rust"],
        find_insensitive(search, content)
    );
}

通过借助第三饭库来使得测试更容易,

assert_cmd

可以处理结果进行断言;也可以测试调用命令进行测试。一起配合使用的还有predicates用来断言布尔值类型结果值

因为测试示例只在开发阶段需要,则在安装时加参数--dev

$> cargo add assert_cmd predicates --dev

新增一个处理文件不存在的的测试示例。日志打印输出时会包含有could not read file字符串。

use assert_cmd::prelude::*;
use ifun_grep::{find, find_insensitive};
use predicates::prelude::*;
use std::{error::Error, process::Command};

#[test]
fn file_doesnt_exist() -> Result<(), Box<dyn Error>> {
    let mut cmd = Command::cargo_bin("ifun-grep")?;

    cmd.arg("-s let").arg("-f 1.txt");
    cmd.assert()
        .failure()
        .stderr(predicate::str::contains("could not read file"));

    Ok(())
}

通过运行cargo test,测试示例是运行成功的。

assert_fs用于测试文件系统的断言

刚才测试了文件不存在的错误输出,还需要增加文件存在的测试,并写入内容。

$> cargo add assert_fs --dev

生成要测试的文件;断言测试生成的文件。tests/lib.rs增加测试用例

use assert_cmd::prelude::*;
use assert_fs::prelude::*;
use ifun_grep::{find, find_insensitive};
use predicates::prelude::*;
use std::{error::Error, process::Command};

#[test]
fn file_content_exist() -> Result<(), Box<dyn Error>> {
    let file = assert_fs::NamedTempFile::new("1.txt")?;
    file.write_str("hello world \n Rust-web \n good luck for you!")?;

    let mut cmd = Command::cargo_bin("ifun-grep")?;

    cmd.arg("-s good").arg("-f").arg(file.path());
    cmd.assert()
        .success()
        .stderr(predicate::str::contains("good luck for you!"));

    Ok(())
}

这样书写的单元测试用例更能直接、明了。和实际使用ifun-grep时同样的命令操作,而不是使用开发时运行cargo run

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/658067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux MTD子系统(二)——mtdblock驱动分析

在之前的文章Linux MTD子系统(一)中有提到过mtd块设备&#xff0c;mtd块设备是在MTD设备之上模拟的块设备。 它的作用实际上只有一个——便于我们使用mount(umount)挂载(卸载)MTD设备中的文件系统&#xff0c;例如yaffs2&#xff0c;JFFS2等等。 本文将介绍mtdblock是如何实现…

LIN总线协议-调度表

文章目录 一、调度表只有一个调度表时&#xff0c;采用循环执行三个调度表存在时&#xff0c;顺序执行调度表发生中断 二、总结 一、调度表 调度表规定了总线上帧的传输次序&#xff08;调度Header&#xff09;以及各帧在总线上的传输时间。 调度表位于主机节点&#xff0c;主…

算法刷题-字符串-左旋转字符串

反转个字符串还有这么多用处&#xff1f; 题目&#xff1a;剑指Offer58-II.左旋转字符串 力扣题目链接 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如&#xff0c;输入字符串"abcdefg"和数字2…

C++算法:单源最短路径Dijkstra

文章目录 前言一、Dijkstra算法思想二、算法实现1、建立图2、代码实现 总结 前言 如果你有一份北京地图&#xff0c;想从中关村走到三元桥&#xff0c;那么怎样能找出实现这一目的的最短路径呢?一种可能的方法就是将这两点之间所有的路线都找出来&#xff0c;然后求出每条路线…

openSUSE项目近日宣布openSUSE Leap 15.5的发布和全面供应

openSUSE项目近日宣布openSUSE Leap 15.5的发布和全面供应&#xff0c;该版本是openSUSE变体的最新稳定版本&#xff0c;针对那些希望为其个人电脑提供基于SUSE Linux Enterprise 15的经过良好测试的操作系统的用户。 openSUSE Leap 15.5是在openSUSE Leap 15.4的一年后推出的&…

Vue中如何进行音频可视化与音频频谱展示

Vue中如何进行音频可视化与音频频谱展示 随着音频应用程序的不断发展&#xff0c;音频可视化和音频频谱展示成为了重要的功能。在Vue应用程序中实现音频可视化和音频频谱展示可以帮助用户更好地了解音频文件的内容和特征。本文将介绍如何在Vue应用程序中实现音频可视化和音频频…

Opensearch基本介绍

OpenSearch 是一个社区驱动的开源搜索和分析套件&#xff0c;开发人员使用该套件来摄取、搜索、可视化和分析数据。 OpenSearch 由数据存储和搜索引擎 (OpenSearch)、可视化和用户界面 (OpenSearch Dashboards) 以及服务器端数据收集器 (Data Prepper) 组成。 用户可以使用一系…

把数字中国,建立在行业感知的底座上

5月23日&#xff0c;国家互联网信息办公室发布了《数字中国发展报告&#xff08;2022年&#xff09;》。报告显示&#xff0c;2022年中国数字经济规模达到50.2万亿元&#xff0c;占国内生产总值比重提升至41.5%&#xff0c;总量居世界第二。如今数字中国最主要的发展挑战&#…

MIFARE - 1

2一般说明 飞利浦根据ISO/IEC 14443A开发了用于非接触式智能卡的MIFAREMF1 IC S50。通信层&#xff08;MIFARERF接口&#xff09;符合ISO/IEC 14443A标准的第2部分和第3部分。安全层采用经过现场验证的CRYPTO1流密码&#xff0c;用于MIFAREClassic系列的安全数据交换。 MIFARE…

GPT中的temperature参数不是用在对话的而是用在调用OPEN API过程中的

前言 自从吴恩达OPENAI《ChatGPT 提示工程》放出后,各个层面反响热列。很多人看到了temperature这个参数,都以为在对话中或者说对话的末尾放上一个temperature=0-2的值就可以达到让GPT极大的发挥出自我创造能力、甚至写文章天马行空。 笔者这边觉得有义务指出这种用法是完全…

OpenAI ChatGPT 使用示例(程序员)

1.编程应用 1.1. 生成例子代码(Coding Generation) ChatGPT帮助我们生产我们需要的例子代码。而且准确率很高。即使你不懂某一种语言也没关系&#xff0c;一定程度上较低了程序员的的门槛。 我有三组数据&#xff0c;第一组是星期一到星期五&#xff0c;第二组是这一天的具体…

第七十八天学习记录:高等数学:微分方程(宋浩板书)

微分方程&#xff08;Differential equation&#xff09;是描述自然现象中变量之间关系的数学语言。它是以函数、导数、微分等数学概念为基础的方程&#xff0c;揭示了自然现象中变量之间的内在联系。微分方程在物理学、工程学、生物学、经济学、统计学等各领域都有广泛的应用。…

C++线程库(2)

C线程库&#xff08;2&#xff09; 线程同步互斥锁条件变量与互斥锁的搭配使用举例1举例2举例3 线程同步 在C线程库&#xff08;1&#xff09;的博客中说了互斥量只能解决多个线程访问共享资源的问题&#xff0c;但是很明显没有次序感&#xff0c;而线程安全就是不同线程访问资…

最短路径算法-迪杰斯特拉(Dijkstra)算法(记录最短路径和距离)

原理&#xff1a; Dijkstra算法是解决**单源最短路径**问题的**贪心算法** 它先求出长度最短的一条路径&#xff0c;再参照该最短路径求出长度次短的一条路径 直到求出从源点到其他各个顶点的最短路径。 首先假定源点为u&#xff0c;顶点集合V被划分为两部分&#xff1a;集合…

chatgpt赋能python:Python字符串去除多余空格

Python字符串去除多余空格 随着Python在各个领域的应用越来越广泛&#xff0c;很多工程师都会遇到字符串去除多余空格的需求。而Python提供了简单的方法来解决这个问题&#xff0c;本文将详细介绍这些方法。 介绍 在Python中&#xff0c;字符串是很常见的数据类型&#xff0…

Linux环境下的工具(yum,gdb,vim)

一&#xff0c;yum yum其实是linux环境下的一种应用商店&#xff0c;主要用centos等版本。它也有三板斧&#xff1a;yum list,yum remove,yum install。当然不是说他只有这三个命令&#xff0c;还有yum search等等。在这直说以上三个。 yum list其实是查看你所能安装的软件包…

puppet 入门详解 超详细!!!

目录 一、puppet概述 二、Puppet的工作模式是什么&#xff1f; 三、Puppet的适用场景是什么&#xff1f; 四、原理 &#xff08;一&#xff09;工作模型 &#xff08;二&#xff09;工作流程 &#xff08;三&#xff09;使用模型 1、单机使用模型 2、master/agent 模型 &…

Vue中如何进行自动化部署与持续集成(CI/CD)

Vue中如何进行自动化部署与持续集成&#xff08;CI/CD&#xff09; 随着云计算和容器技术的广泛应用&#xff0c;自动化部署和持续集成&#xff08;CI/CD&#xff09;已经成为现代软件开发过程中必不可少的环节。Vue作为一款流行的前端框架&#xff0c;也可以使用自动化部署和…

解决:闹钟设置的自定义歌曲响铃时不会播放仅震动【Apple Music】【iOS】

文章目录 1、问题描述2、解决策略3、Q&A4、感受5、Tips 1、问题描述 自带铃声和震动脑瓜子嗡嗡的&#xff0c;幸好有apple music&#xff0c;在闹钟中可以轻松地选择你放入资料库中的任意一首音乐作为铃声。 奇怪的是&#xff0c;闹钟响起&#xff0c;仅震动&#xff0c;没…

chatgpt赋能python:Python怎么过滤非数字

Python怎么过滤非数字 在实际编程过程中&#xff0c;我们常常遇到要对一些数据进行处理&#xff0c;其中经常需要过滤掉非数字的数据&#xff0c;以保证程序能够正常运行。在Python中&#xff0c;若要过滤非数字&#xff0c;可以采用如下几种方法。 方法一&#xff1a;使用正…