首页 > 其他分享 >rust语法 3

rust语法 3

时间:2023-03-19 20:13:48浏览次数:47  
标签:join string 语法 let fn Rc println rust

测试

单元测试

测试单一模块,且能够测试私有接口。

创建 tests 模块并使用 #[cfg(test)] 注解。一般测试模块与目标函数放置于同一个文件。

使用 cargo test 运行测试,cargo test name_slice 可运行指定测试

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}
// 私有方法也可测试
fn bad_add(a: i32, b: i32) -> i32 {
    a - b
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;

    #[ignore = "这个属性能用于忽略测试"]
    #[test]
    fn test_add() {
        assert_eq!(add(1, 2), 3);
    }

    // 测试函数也可以返回 Result
    #[test]
    fn test_bad_add() -> Result<(), String> {
        if 2 == bad_add(1, 1) {
            Ok(())
        } else {
            Err("the function is bad".to_owned())
        }
    }

    #[test]
    #[should_panic(expected="should panic")] // 当希望发生 panic 时使用
    fn test_should_panic() {
        panic!("should panic")
    }
}

文档测试

文档注解支持commonMarkdown格式,其中的代码块在 cargo test 时也执行。

集成测试

cargo将集成测试放在与src平级的tests目录中,只能使用公开接口。
可以将所有测试都需要的初始设置放入一个函数,再引入test

例如:

// tests/common/mod.rs
pub fn setup() {
    // some setup code, like creating required files/directories, starting
    // servers, etc.
}
// importing common module.
mod common;

#[test]
fn test_add() {
    // using common code.
    common::setup();
    assert_eq!(adder::add(3, 2), 5);
}

开发期依赖

 引入后只在开始时有效

# standard crate data is left out
[dev-dependencies]
pretty_assertions = "1"

Vector

可变长的数组,一个vector对象有3个组成部分:指向数据的指针,长度,容量。

fn main() {
    let mut v1: Vec<i32> = (0..10).collect();
    let mut v2 = vec!["a", "b", "c"];
    println!(
        "{} {} {} {}", // 10 10 3 3
        v1.len(),
        v1.capacity(),
        v2.len(),
        v2.capacity()
    );

    for (_i, x) in v1.iter_mut().enumerate() {
        *x *= 2;
    }

    v2.append(&mut vec!["d", "e", "f", "g"]);
    println!(
        "{} {} {:?}", // 7 7 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
        v2.len(),
        v2.capacity(),
        v1
    );
}

字符串

Rust中有两种字符串:String 和 &str。String是存储在堆上的字节vector,是不以null结尾的utf8字符。&str是指向utf8序列的切片,指向String。

std::str 和 std::string 专门用于处理 str 和 string 类型。

fn main() {
    let s: &'static str = "this is a string data"; // 字面量分配在常量区,只读
    println!("{:p} : {}", s.as_ptr(), s);

    for word in s.split_whitespace().rev() {
        println!("{:p} : {}", word.as_ptr(), word);
    }

    let S = String::from("this is a string data");
    let ss = s.replace("string", "String");
    println!("{:p}", S.as_str());
    println!("{:p}", ss.as_str());
}
// print:
// 0x7ff6dbc656e8 : this is a string data
// 0x7ff6dbc656f9 : data
// 0x7ff6dbc656f2 : string
// 0x7ff6dbc656f0 : a
// 0x7ff6dbc656ed : is
// 0x7ff6dbc656e8 : this
// 0x2699c84f380
// 0x2699c8522c0

智能指针

Box

类似c++的 unique_ptr

智能指针,rust中对象默认分配栈上。可通过 Box 使其分配到堆上,当Box离开作用域时指针和内部对象都销毁。可以通过 * 操作符解引用,直接获得内部对象。

#[derive(Debug, Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
}
fn main() {
    let p = Point { x: 1.0, y: 2.0 };
    let bp = Box::new(p);
    println!(
        "{} {} {}", // 16 8 16
        std::mem::size_of_val(&p),
        std::mem::size_of_val(&bp),
        std::mem::size_of_val(&*bp)
    );
}

Rc

Rc(Reference Counting)是对内部对象的引用计数指针,类似c++的 shared_ptr 和 weak_ptr。

内部分为强引用和弱引用,弱引用用于防止循环引用。

fn main() {
    let s = "xxx".to_string();
    let s1 = Rc::new(s);
    println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 1 0
    {
        let _s2 = Rc::clone(&s1);
        println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 2 0
    }
    {
        println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 1 0
        let s3 = Rc::downgrade(&s1);
        println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 1 1
        let _s4 = s3.upgrade();
        println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 2 1
    }
    println!("{} {}", Rc::strong_count(&s1), Rc::weak_count(&s1)); // 1 0
}

Arc

Arc(Atomically Reference Counted)用于多线程间共享所有权。

use std::{sync::Arc, thread};

fn main() {
    let s = Arc::new("string");

    let mut join_vec = vec![];

    for _ in 0..10 {
        let ss = Arc::clone(&s);
        let join = thread::spawn(move || {
            println!("{:?} {:?} {:p}", ss, Arc::strong_count(&ss), ss.as_ptr());
        });
        join_vec.push(join);
    }
    join_vec.into_iter().for_each(|j| {
        let _ = j.join();
    });
}
// "string" 5 0x7ff7f8e29f38
// "string" 6 0x7ff7f8e29f38
// "string" 9 0x7ff7f8e29f38
// "string" 11 0x7ff7f8e29f38
// "string" 10 0x7ff7f8e29f38
// "string" 10 0x7ff7f8e29f38
// "string" 9 0x7ff7f8e29f38
// "string" 9 0x7ff7f8e29f38
// "string" 8 0x7ff7f8e29f38
// "string" 8 0x7ff7f8e29f38

多线程

 一个简单 map-reduce 程序

MapReduce
 use std::{collections::HashMap, thread};

fn main() {
    let data = "86967897737416471853297327050364959
11861322575564723963297542624962850    
70856234701860851907960690014725639
38397966707106094172783238747669219
52380795257888236525459303330302837
58495327135744041048897885734297812
69920216438980873548808413720956532
16278424637452589860345374828574668";
    let mut join_vec = vec![];

    let chunked_data = data.split_whitespace();

    for (i, segment) in chunked_data.enumerate() {
        join_vec.push(thread::spawn(move || -> HashMap<u32, i32> {
            let mut map = HashMap::new();

            segment.chars().for_each(|c| {
                let num = c.to_digit(10).expect("should be digit");

                match map.get_key_value(&num) {
                    Some((&k, &v)) => {map.insert(k, v + 1);}
                    None => {map.insert(num, 1);}
                }
            });
            println!("thread {i} get result: {:?}", map);
            map
        }));
    }
    let mut final_result = HashMap::new();
    join_vec.into_iter().for_each(|res| {
        match res.join() {
            Ok(map) => {
                map.iter().for_each(|(&k, &v)| {
                    match final_result.get(&k) {
                        Some(old_result) => {
                            final_result.insert(k, v + old_result);
                        },
                        None => {
                            final_result.insert(k, v);
                        },
                    }
                });
            },
            Err(err) => {
                println!("thread fail: {:?}", err);
            },
        }
    });
    println!("final result: {:#?}", final_result);
}

标准库的 channel 支持多sender,1个receiver。第三方库 crossbeam_channel 支持多个生产者和消费者。

use std::{sync::mpsc, thread};

static THREAD_NUM: i32 = 3;

fn main() {
    let (sender, receiver) = mpsc::channel();

    let mut join_vec = vec![];

    for i in 0..THREAD_NUM {
        let sender2 = sender.clone();
        let join = thread::spawn(move || {
            sender2.send(i).unwrap();
            println!("thread {i} send: {i}");
        });
        join_vec.push(join);
    }

    for _ in 0..THREAD_NUM {
        receiver.recv().map_or_else(
            |err| println!("err: {err}"),
            |recv| println!("recv: {recv}"),
        );
    }

    for j in join_vec {
        j.join().expect("the child thread panic");
    }
}

IO

 *nix 和 windows 内部使用不同的格式保存字符串,所以Path对应的路径表示不是uft8格式字符串,而是依赖平台的 OsStr。Path 依赖 OsStr 创建,是不可变的。PathBuf 是可变的,与 Path 相关的。关系类似String 和 str。Path 转换为字符串可能失败,但一定可转换为 OsStr。

use std::path::Path;

fn main() {
    let cur_path = Path::new(".");
    let mut new_path = cur_path.join("a").join("b");
    new_path.push("c");
    new_path.push("file.txt");

    println!("{:?} {:?}", cur_path, new_path);
}

文件操作:

use std::{
    fs::{self, File},
    io::{self, Write, BufRead},
    path::Path,
};

fn main() -> io::Result<()> {
    let file_path = Path::new("D:/tmp.txt");
    if file_path.try_exists()? {
        fs::remove_file(file_path)?;
    }

    {
        let mut f = File::create(file_path)?;
        f.write(b"123456\nabcdef")?;
    }

    let file = match File::open(file_path) {
        // 当 File 对象超出作用域时,自动释放资源
        Ok(file) => file,
        Err(err) => panic!("open file failed: {}", err),
    };

    // file.read_buf()
    for ele in io::BufReader::new(file).lines() {
        if let Ok(line) = ele {
            println!("{line}");
        }
    }

    Ok(())
}

 子进程

use std::{io, process::Command};

fn main() -> io::Result<()> {
    let output = Command::new("rustc").args(["--version"]).output()?;
    if output.status.success() {
        let s = String::from_utf8_lossy(&output.stdout);
        println!("successded:\n{}", s);
    } else {
        let s = String::from_utf8_lossy(&output.stderr);
        println!("fail:\n{}", s);
    }

    Ok(())
}

标签:join,string,语法,let,fn,Rc,println,rust
From: https://www.cnblogs.com/zhh567/p/17224259.html

相关文章

  • rust使用json
    JSON作为使用最广泛的数据结构,学习了解如何在发展最快的Rust语言中使用很有必要。本文中我们将学习到:读取无类型的JSON。将JSON读取为强类型数据结构。写JSON......
  • 正则表达式的语法
    4.2.1正则表达式的语法正则表达式是对字符串操作的一种逻辑公式,它会将事先定义好的一些特定字符以及他们的组合组成一个规则字符串,并且通过这个规则字符串表达对给定字符串......
  • Vue2入门之超详细教程三-初识模板语法
    1、简介模板语法就是按照固定的模板去书写代码,分为插值语法和指令语法。差值语法:功能:用于解析标签体内容写法:{{xxxx}},xxx是js表达式,且可以读取......
  • storybook 编写stories的story基础语法
    编写storiesstory用于展示组件某个状态,每个组件可以包含任意多个story,用来测试组件的各种场景。根据默认配置,只需要在组件的文件夹中,以 **.component.stories.ts 的......
  • 【CSS】盒子模型内边距 ① ( 内边距概念 | 内边距设置语法 | 内边距设置效果 | 代码示
    文章目录​​一、内边距​​​​1、概念​​​​2、内边距设置语法​​​​3、内边距设置效果​​​​二、内边距代码示例​​​​1、不设置边距的示例​​​​2、设置边距......
  • Markdown语法详解
    Markdown语法详解标题+空格+要写的东西=一级标题+空格+要写的东西=二级标题+空格+要写的东西=三级标题+空格+要写的东西=四级标题+空格+要写的东西=五级标题+空格+......
  • 【 Python 】补全fibersim 导出的xml语法
    fibersim导出的xml文件中,node和mesh部分的标签会缺失。即<R></R>变成了<R/>.以下python脚本可以自动修正importref2=open('x13.xml','w')withopen('E:\\20230314......
  • 万字血书Vue—Vue语法
    模板语法插值语法Mustache插值采用{{}},用于解析标签体内容,将Vue实例中的数据插入DOM中<h1>Hello{{name}}</h1>指令语法指令用于解析标签,是vue为开发者提供的一套......
  • DTD语法规则
    元素的定义:  属性的定义:  <?xmlversion="1.0"encoding="UTF-8"?><!--第三种引入约束的方式就是用网络中的dtd文件引入约束--><!DOCTYPEstudentsPUB......
  • Python脚本运行出现语法错误:IndentationError:unexpected indent
    【问题】 一个python脚本,本来都运行好好的,然后写了几行代码,而且也都确保每行都对齐了,但是运行的时候,却出现语法错误: IndentationError: unexpectedindent【解决过程......