leetcode--1.两数之和
两数之和
这个问题如果使用最简单的办法是暴力破解,它的运行时间会比较长,而且时间复杂度为O(n^2)
使用哈希表处理较为方便: 哈希表 通过`key`来锁定每一个值对应的下标,也就是说哈希表要设置成`hash(val,idx)`,索引在后,hash在前的方法,通过target 的方法来对照HashMap,查找对应的索引,将正在索引 的idx和HashMap对应的idx返回。
代码 blue
12345678910111213use std::collections::HashMap;impl Solution {pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> { let mut hash = HashMap::with_capacity(nums.len()); for (idx,&val) in nums.iter().enumerate() { if let Some(&find) = hash.get ...
通过例子学习Rust--23.兼容性
兼容性
rust自己有许多关键字需要进行使用,这个时候如果我们想要使用这个关键字,就需要使用原始标志符重写代码
通过例子学习Rust--22.不安全操作
不安全操作
减少不安全代码的使用量,它主要用在以下几个方面:
解引用裸指针
通过 FFI 调用函数(外部语言调用函数接口)
调用不安全的函数
内联汇编(inline assembly)
原始指针
和&T有类似的功能,但是不能够保证指针指向地域数据有效。
调用不安全函数
一些函数必须由程序员自己负责,因为这些程序(如指针必须指向有效的内存)。
通过例子学习Rust--21.测试
测试
Rust自身支持测试,有三种风格:
单元测试
文档测试
集成测试
也可以在测试中指定额外的依赖
单元测试
单元测试基本上会被放在叫做tests,有着#[cfg(test)]属性的模块之中。测试要加上#[test]属性。
某些函数在特定状态下会产生panic,如果想要测试成功并且使用这种属性,添加#[should_panic]属性。同时可以指定panic状态值下的消息,通过expect指定。
可以运行特定的测试、可以运行被忽略的测试。
文档测试
这种方法在你发布crate很有用,使用markdown语法,并且支持test
开发依赖
如果仅仅需要在测试中使用的依赖,一般放在Cargo.toml里面的[dev-dependencies]之中。
通过例子学习Rust--20.标准库更多介绍
标准库更多介绍
标准库提供了很多其他类型支持某些功能,如:
线程(Threads)
信道(Channels)
文件输入输出(File I/O)
线程
Rust通过spawn函数提供了创建本地操作系统的机制,该函数参数是通过值捕获变量的闭包
12345678910111213141516171819202122use std::thread;static NTHREADS: i32 = 10;// 这是主(`main`)线程fn main() { // 提供一个 vector 来存放所创建的子线程(children)。 let mut children = vec![]; for i in 0..NTHREADS { // 启动(spin up)另一个线程 children.push(thread::spawn(move || { println!("this is thread number {}", i) })); ...
通过例子学习Rust--19.标准库类型
标准库类型
rust标准库有许多自定义类型:
可增长的 String(字符串),如: “hello world”
可增长的向量(vector): [1, 2, 3]
选项类型(optional types): Option
错误处理类型(error handling types): Result<i32, i32>
堆分配的指针(heap allocated pointers): Box
箱子、栈和堆
默认会在栈中分配,可以使用Box<T>将值装箱 ,就能够在堆上分配空间了。
Box是一个智能指针,指向堆分配的T类型的值,当离开时作用域,会自动调用析构函数,内部对象被销毁,堆上分配内存被释放。
使用*进行解引用,会移除一层装箱(这项当于C语言中的指针)
box的宽度就是指针的宽度。
使用mem::size_of_val(&T)可以进行地址大小检测。
(不知道和C语言中是否一样满足struct的补齐原则)
动态数组vector
vector和slice都是编译时大小未知,可以随时扩大或者缩小。
&[T]是Vec的全部或部分引用。
vec ...
通过例子学习Rust--18.错误处理
错误处理
panic
如果符合直接panic字符串并且退出。
Option和unwrap
option是一种可能遇到不存在的情况,它可能会遇到Some(T)和None两种情况。
option可以和match进行组合,或者是使用unwrap进行隐式处理(返回Some(T)或者panic)
使用?解开Option
首先使用Option嵌套struct,然后使用?进行嵌套。
组合算子:map
遇到只有一种输入有效的情况之下,使用组合算子 来以模块化的风格管理控制流。
Option有一个内置方法map,用于Some-Some和None->None。多个map()调用串联,更加灵活。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#![allow(dead_code)]#[derive(Debug)] enum Food { Apple, Carrot, Potato }#[deriv ...
通过例子学习Rust--17.使用macro_rules!创建宏
使用macro_rules!创建宏
Rust中宏系统可以让其进行元编程,宏的定义和函数的区别在于有没有!。宏不会产生调用,会被编译成源码和其他部分一起编译。
宏定义的最后一个分支可以不使用分号作为结束。
参数使用$进行标注,参数类型如果是expression,使用:expr标注;参数名标注使用:ident;运算符和标记使用tt标记。
多个参数根据实际情况,如果是>=1使用+;>=0使用*。
DRY(不重复写代码)
没咋看明白。
通过例子学习Rust--16.trait
特质trait
对未定义的Self定义的方法集,定义trait之后将其作用于impl块中。
对任何数据类型都可以实现trait。
派生
通过#[derive]属性,编译器提供某些trait基本实现。更复杂的行为可以手动实现所需要的trait。
使用dyn返回trait
Rust编译器决定了每个函数返回值需要多少空间,这意味着每个函数都必须返回一个具体类型。因此trait不能做为函数的返回值来使用,因为不同的实现造成了trait需要不同的内存量。
因此使用Box返回包含一些trait的引用更为方便,因为引用的大小是已知的,使用引用指向已分配堆中的trait,这样就能返回trait了。
返回指向堆的trait指针,需要使用关键字dyn来定义,如Box<dyn Animal>。
运算符重载
Rust中很多运算符通过trait来重载。
Drop
Drop trait只有一个方法:drop,它会在对向离开作用域的时候自动调用该方法,它的作用是释放实现者的实例拥有的资源。
Box,Vec,String,File,以及 Process 是一些实现了 Drop tr ...
通过例子学习Rust--15.作用域规则
作用域规则
主要是针对所有权、借用、生命周期规范
RAII
Rust中强制进行RAII资源获取即初始化 ,在任何对象离开作用域的时候会调用它的析构函数,因此不需要手动释放内存,避免了资源泄露 。
析构函数通过Drop 提供,自定义的类型需要自己实现drop trait,其余的自动实现了这种trait。
所有权和移动
因为变量要进习释放所用有的资源,因此只有一个所有者,因此就有了引用 这种方法。
指针指向堆地址,如果进行移动,这个时候之前的指针会失去作用,新的指针会拥有原来堆上的内存原来指针会失效 ,手动执行释放后,新的指针也不能访问。
而对于变量的移动,让两个变量拥有相同的值,两个变量是都可以访问的。
可变性
可变指针可以进行修改指针指向的内容,但是不可变指针不行。所有权 转移:由不可变指针->可变指针,会得到这样的结果。
部分移动
在对结构体进行解构的过程中,可以使用ref关键字进行绑定,绑定过ref的参数属于是引用的参数。而没有标注的则是move模式。
借用
借用&T的存在巧妙解决了所有权T和使用中的问题。
编译器通过借用检查,保证了引用总是指向有 ...