Rust语言开发基础(五)语言数据类型

释放双眼,带上耳机,听听看~!

**一. 基本介绍
**
虽然是静态类型语言,但是定义变量,不用定义类型,只用关键字声明即可,即用关键字 let ,Rust 有类型推断,用以平衡强大的静态类型和冗长标注类型。
let x = "hello, world!";
let a="foobar";
let b="foo\
bar";

let mut x = vec!["Hello", "world"];  使用名字叫“vec”的宏(感叹号表示宏),将这个宏绑定到一个叫“x”的变量上。
Rust 更倾向于堆栈分配而不是堆分配:x 被直接放置在堆栈中。然而,Vec<T> 类型是在堆上分配的向量元素的空间。
这个let体现的是Rust中的“所有权”概念。
我们将Rust语言类型分为两种来说明,即基本类型和集合。

二. 基本类型

1.字符和字符串

字符类型     :let a = 'b';
字符串类型  : let a = "abcdef";
行类型        : let a = r#abcdef#;

字节字符类型   :let a = b'a';
字节字符串类型:let a = b"abcdef";
字节行类型      : let a = br#abcdef#;
前缀b=bite字节, r=row行

\字符串换行符,也是转义字符的标识。
let a = "foobar";
let b = "foo\
bar";
a和b是相等的字符串。

Rust包含2个字符串类型:String 和 &str
**A. &str **称为“字符串切片”,固定大小,并且不可改变(string slice )。
比如: let a = "hello world"  //那么a就是一个字符串切片
"hello world" 是一个“本义字符串”(string literal,即直接双引号内拼写出来的字符串)并且是静态的字符串,一个“本义字符串”属于是一个字符串切片,是静态分配的,它被保存在编译的程序中,在整个程序运行过程都存在,类似java中的静态变量,那么a呢,就是一个绑定,换个说法,就是一个引用,引用那个静态分配的字符串,所有功能想要得到一个字符串切片的,都会得到一个“本义字符串”。
为什么作者要称这个为字符串切片(slice)呢?是因为这种字符是随时可以切成一个一个字符的!

 

**B. String **
堆分配,可增长,保证是UTF-8编码,通常是由一个字符串切片通过to_string方法强制转换过来的。


1
2
3
4
5
1let mut s = &quot;Hello&quot;.to_string();  // mut s: String
2println!(&quot;{}&quot;, s);
3s.push_str(&quot;, world.&quot;); //增加值,即可增长
4println!(&quot;{}&quot;, s);
5

使用一个&符号可以将Strings类型强制转换为&str类型


1
2
3
4
5
6
7
8
1fn takes_slice(slice: &amp;str) {
2    println!(&quot;Got: {}&quot;, slice);
3}
4fn main() {
5    let s = &quot;Hello&quot;.to_string();
6    takes_slice(&amp;s);
7}
8

关键点:记住String类型分配内存控制它的数据, &str是一个指向另一个字符串的引用,知道这些就可以了。
String 转换成 &str内存成本是比较低的,但是 &str 转换成 String 因为涉及到内存分配,转换成本比较高,所以如果没有必要不要去转换。

usestd::net::TcpStream;

TcpStream::connect("192.168.0.1:3000"); // &str parameterletaddr_string="192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // 转换 addr_string 到 &str

**总结:
**
str 是不可变的字符串;
std::String 是可变的字符串;
std::ffi::CStr 用于表示由C分配、rust借用的C字符串;
std::ffi::CString 用于表示由rust分配、可以传递给C函数使用的C字符串;
std::ffi::OsStr 平台相关的字符串,具体看 rust/os_str.rs at master · rust-lang/rust · GitHub;
std::ffi::OsString 这个是上面的可变版本;
std::path::Path 用来表示路径,方法和普通字符串不一样,当然独立出来;
std::path::PathBuf 这是Path的可变版本;
总之普通字符串就用str和String,路径就用Path和PathBuf,其他是ffi才需要用到的。
OsStr/OsString 这两个都是为 Path 而存在

2. 数值

十进制整型(Decimal integer):98_222
十六进制整型(Hex integer)   :0xff
八进制整型(Octal integer)    :0o77
二进制整型(Binary integer)   :0b1111_0000
浮点型(Floating-point)         :123.0E+77

数值的后缀
Integer Floating-point
u8, i8, u16, i16, u32, i32, u64, i64, isize, usize f32, f64
数值后缀标明该数值的存储空间
比如整型的数值


1
2
3
4
5
6
7
8
1123i32;                            // type i32
2123u32;                            // type u32
3123_u32;                           // type u32
40xff_u8;                           // type u8
50o70_i16;                          // type i16
60b1111_1111_1001_0000_i32;         // type i32
70usize;                            // type usize
8

默认是i32

浮点型的后缀


1
2
3
4
5
6
1123.0f64;        // type f64
20.1f64;          // type f64
30.1f32;          // type f32
412E+99_f64;      // type f64
5let x:f64=2.;    // type f64
6

默认是f64

  1. 布尔值

true and false

**三、集合

  1. 数组

**
特性:固定大小,存放同类型元素,不可变。
let a = [1, 2, 3];     //数组类型是 a: [i32; 3]
let mut m = [1, 2, 3];    //数组类型是 mut m: [i32; 3]

A. 数组类型的表达–[T;N] 其中T指泛型。

B. 数组简单初始化方法:let a = [0; 20]; // a: [i32; 20],即初始化20个元素,每个元素为0。

C. 数组长度:a.len()。

D. 数组遍历:


1
2
3
4
5
6
1let a = [1, 2, 3];
2println!(&quot;a has {} elements&quot;, a.len());
3for e in a.iter() {
4    println!(&quot;{}&quot;, e);
5}
6

E. 数组特定访问:


1
2
3
1let names = [&quot;Graydon&quot;, &quot;Brian&quot;, &quot;Niko&quot;];   // names: [&amp;str; 3]
2println!(&quot;The second name is: {}&quot;, names[1]);  // 注意下标也是从0开始
3

**2. 向量 
**
特性:可增长的数组, 可变并且自动增长,内存堆分配,类似字符串当中 与&str对应的String,可用宏vec!创建。


1
2
3
4
1let v = vec![1, 2, 3]; // v: Vec&lt;i32&gt;let mut nums = vec![1, 2, 3]; // mut nums: Vec&lt;i32&gt;
2nums.push(4);
3println!(&quot;The length of nums is now {}&quot;, nums.len()); // Prints 4
4

 

**3. 切片
**
特性:是引用(查看)一个数组部分数据,对于需要安全,高效访问数组的部分数据十分有用,并且不需 要拷贝。例如,你只想将一个文件的一行数据读进内存。
切片不是凭空创建的,而是来自一个存在的变量,切 片有长度,可变或者不可变都可以,使用的方式类似数组:


1
2
3
4
5
6
1let a = [0, 1, 2, 3, 4];
2let middle = &amp;a[1..4];      // a的切片。包含元素1,2,3  范围是[ )  实-虚
3for e in middle.iter() {
4    println!(&quot;{}&quot;, e); // Prints 1, 2, 3
5}
6

 

**4. 元组
**元组是一个有固定大小的有序列表,里面可以存放任何数据类型的值
let x = (1,"hello") //简单元组
let x: (i32,&str) = (1,"hello");   // 有说明数据类型的元组

let (x,y,z)=(1,2,3);   //模糊匹配,同时初始化3个变量
println!("x is {}",x);

**A. 元组的分配引用
**
let mut x = (1, 2); // x: (i32, i32)
let y = (2, 3); // y: (i32, i32)
x = y;

 

**B. 元组的判断
**
let x = (1, 2, 3);
let y = (2, 2, 4);
if x == y {
println!("yes");
} else {
println!("no");
}

**C. 用于函数返回多个值
**
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }fn main() {    let (x, y) = next_two(5);    println!("x, y = {}, {}", x, y);}

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C++ 中 struct和class 的区别

2022-1-11 12:36:11

安全经验

大型网站压力测试及优化方案

2021-11-28 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索