主頁 > 後端開發 > rust 使用第三方庫構建mini命令列工具

rust 使用第三方庫構建mini命令列工具

2023-06-18 07:49:48 後端開發

這是上一篇 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 <[email protected]>")]
#[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 = "https://www.cnblogs.com/dreamHot/archive/2023/06/18/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

追逐的不應該是夢想,隨心所欲,隨遇而安!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555456.html

標籤:其他

上一篇:[ARM 匯編]進階篇—例外處理與中斷—2.4.2 ARM處理器的例外向量表

下一篇:返回列表

標籤雲
其他(161197) Python(38240) JavaScript(25504) Java(18245) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7256) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4601) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • rust 使用第三方庫構建mini命令列工具

    這是上一篇 [rust 學習 - 構建 mini 命令列工具](https://www.cnblogs.com/dreamHot/p/17467837.html)的續作,擴展增加一些 crate 庫。這些基礎庫在以后的編程作業中會常用到,他們作為基架存在于專案中,解決專案中的某個問題。 專案示例還是 ......

    uj5u.com 2023-06-18 07:49:48 more
  • [ARM 匯編]進階篇—例外處理與中斷—2.4.2 ARM處理器的例外向量

    #### 例外向量表簡介 在ARM架構中,例外向量表是一組固定位置的記憶體地址,它們包含了處理器在遇到例外時需要跳轉到的處理程式的入口地址。每個例外型別都有一個對應的向量地址。當例外發生時,處理器會自動跳轉到對應的向量地址,并開始執行例外處理程式。 #### 例外向量表的位置 ARM處理器的例外向量表 ......

    uj5u.com 2023-06-18 07:49:41 more
  • 基于回歸分析的波士頓房價分析

    #基于回歸分析的波士頓房價分析 專案實作步驟: 1.專案結構 2.處理資料 3.處理繪圖 4.對資料進行分析 5.結果展示 一.專案結構 ![image](https://img2023.cnblogs.com/blog/3047082/202306/3047082-2023061722315431 ......

    uj5u.com 2023-06-18 07:49:28 more
  • 通過模仿學會Python爬蟲(一):零基礎上手

    好家伙,爬蟲來了 爬蟲,這玩意,不會怎么辦, 誒,先抄一份作業回來 1.別人的爬蟲 Python爬蟲史上超詳細講解(零基礎入門,老年人都看的懂)_ChenBinBini的博客-CSDN博客 # -*- codeing = utf-8 -*- from bs4 import BeautifulSoup ......

    uj5u.com 2023-06-18 07:49:10 more
  • 09. centos使用docker方式安裝mysql

    ## 一、創建宿主機物理路徑 新建/mydata/mysql/data、log和conf三個檔案夾 ```bash mkdir -p /mnt/mysql/log mkdir -p /mnt/mysql/data mkdir -p /mnt/mysql/config ``` 或者 ```bash m ......

    uj5u.com 2023-06-18 07:49:00 more
  • C++面試八股文:聊一聊指標?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第17面: > 面試官:聊一聊指標? > > 二師兄:好的。 > > 面試官:你覺得指標本質上是什么? > > 二師兄:這要從記憶體地址開始說起了。如果有一塊容量是1G的記憶體,假設它的地址是從`0x00000000` 到`0x3fffffff`,每一個 ......

    uj5u.com 2023-06-18 07:48:54 more
  • Java 注釋及Dos命令

    # Java 注釋、絕對路徑、相對路徑、基本Dos命令 # 1. Java的三種注釋方式 ## 注釋能增加代碼的可讀性,習慣寫注釋能提升我們撰寫代碼的能力 > ### 單行注釋:用//注釋一些代碼提示 > > ### 多行注釋:以/*為開頭 以 */為結束 > > ### 檔案注釋:/* > > # ......

    uj5u.com 2023-06-18 07:48:48 more
  • Java基本概念

    # 1.Java 發展歷史 ### 由高斯林創建 1995年由甲骨文公司收購并發出第一版本,目前使用最多是Java8 及 Java11 原因是這兩個版本都是長期支持維護的,企業用的也比較多。 # 2.Java的一些特點 > ### 跨平臺性:主要是因為每個平臺都裝有 JVM > ### Java 是 ......

    uj5u.com 2023-06-18 07:48:44 more
  • Go語言學習總結

    #### 1. 跳出/執行下一次回圈。 ``` {標簽名}: for true { ... for true { ... break/continue {標簽名} //默認不加標簽,則跳出最近一層回圈。加了標簽可以跳出標簽定義處所在回圈 } } ``` #### 2. map的使用注意項。 因為ma ......

    uj5u.com 2023-06-18 07:48:40 more
  • 整理spring-web里支持的檔案以及對應的Content-Type

    最近在弄檔案上傳、下載、在線預覽時經常需要設定請求標頭或者回應標頭的Content-Type 屬性。所以研究了一下spring支持哪些Content-Type,通過研究MediaTypeFactory.getMediaType的原始碼,可以得知spring是將支持的Content-Type 維護在/o... ......

    uj5u.com 2023-06-18 07:48:31 more