四、切片、结构体及枚举使用

112 阅读3分钟

前言

阅读耗时2分钟,基础语法,重要的是后面的泛型以及生命周期,还有单元测试的编写

目录

切片、结构体及枚举使用.png

一、切片

不持有所有权的数据类型
例如找某个数据在字符串下的下标

fn main() {
    let mut s = String::from("Hello Rust!");
    let wordIndex = find_test(&s);
    println!("{} ", wordIndex);
    
}
fn find_test(s: &String) -> usize{
    let bytes = s.as_bytes();
    for(i, &item) in bytes.iter().enumerate(){
        if( item  == b' '){
            return i;
        }
    }
    s.len()
}

换成切片写法,返回字符串

fn main() {
    let mut s = String::from("Hello Rust!");
    let s2 = find_test2(&s);//这块借用成了 一个不可变引用
    // s.clear(); //同一时刻不能存在可变和不可变的引用,可变引用才能清楚
    println!("{} ", s2);
    
}

fn find_test2(s: &String) -> &str{
    let bytes = s.as_bytes();
    for(i, &item) in bytes.iter().enumerate(){
        if( item  == b' '){
            return &s[0..i];
        }
    }
    &s[..]
}

二、结构体

C++ 一样,直接上例子

定义

struct User{
    username: String,
    email: String,
    age: i32,
}
struct  Rectangle{
    width:u32,
    length:u32,
}

使用

fn main() {
    let user1 = User{
            username:String::from("xxx"),
            email: String::from("abc@163.com"),
            age:20,
    };
    //user1.email = String::from("abc@qq.com");//访问报错,必须申明 可变才能修改
    println!("email = {}", user1.email );
    let user2  = User{
        username:String::from("xxx"),
         ..user1
    };
    let rect = Rectangle{
      width:50,
      length : 30,  
    };
    println!("Rectangle Area is {}", area(&rect));
}

fn area(rect: &Rectangle) -> u32{
    rect.width * rect.length
}
struct  Rectangle{
    width:u32,
    length:u32,
}

tuple struct

fn main() {
    let balck = Color(0,1,0);
    println!("color {}", balck.1);
    
}
struct Color(i32, i32,i32);

所有权

fn main() {
    let user1 = User{
            username:String::from("xxx"),
            email: String::from("abc@163.com"),
            age:20,
    };
}

还是通过之前的例子说明,user1 实例持有内部所有属性的所有权,只有user1 是有效的,内部字段都是有效的,包括内部字段是引用

struct 方法

利用implstruct 添加方法,改造一下计算矩形面积示例

fn main() {
    let rect = Rectangle{
      width:50,
      length : 30,  
    };
    println!("Rectangle Area is {}", rect.area());
    
}

struct  Rectangle{
    width:u32,
    length:u32,
}
impl Rectangle{
    fn area(&self) -> u32{
        self.width * self.length
    }
}

方法的第一个参数都是&self 自身传入。毕竟要用到自身的属性,如果不想用自身属性,那么可以使用关联函数,如下

fn main(){
   let r = Rectangle::square(20);
}
impl Rectangle{
    fn area(&self) -> u32{
        self.width * self.length
    }
    fn square(size: u32) -> Rectangle{
        Rectangle { width: size, length:size }
    }
}

特别的toString打印

我们在Java中,直接toString()复写,就能打印出所有实例属性,那么rust中怎么操作呢?
假如我们想打印出Rectangle 中的属性数据

fn main(){
      let rect = Rectangle{
      width:50,
      length : 30,  
    };
    println!("{:?}", rect);
    println!("{:#?}", rect);
}
#[derive(Debug)]
struct  Rectangle{
    width:u32,
    length:u32,
}
输出:
Rectangle { width: 50, length: 30 }
Rectangle {
    width: 50,
    length: 30,
}

结构体上加上 #[derive(Debug)] 标记,并且使用{:?} 模式或者 可以格式化的模式 {:#?}

三、枚举

定义

enum IpType{
    V4,
    V6,
}
enum IpTypeAndValue{
    V4(u8, u8, u8, u8),
    V6(String),
}

示例

fn main()
    let v4 = IpType::V4;
    route(v4);
    let v4Value  = IpTypeAndValue::V4(127, 0 , 0 ,1);
    let v6Value = IpTypeAndValue::V6(String::from("::1"));
}
fn route(ip_type: IpType){  
}

枚举方法

struct一样,也能添加方法

impl IpTypeAndValue {
    fn call(&self){
        println!("枚举 call调用");
    }
}

Option枚举

为什么会有Option? 因为Rust中没有Null,不像c++中 有NULLnullptr
Option在标准库中已经定义好了

pub enum Option<T> {
    /// No value.
    #[lang = "None"]
    #[stable(feature = "rust1", since = "1.0.0")]
    None,
    /// Some value of type `T`.
    #[lang = "Some"]
    #[stable(feature = "rust1", since = "1.0.0")]
    Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}

如何使用呢?

fn main() {
    let some1 = Some(1);
    let some2 = Some("Exception");
    let none :Option<i32> = None;
    if let Some(1) = some1{
        println!("find");
    }else{
        println!("not find");
    }
    match some1{
        Option::Some(i) => {
            println!("option 中的值是 {}", i);
        },
        _ => {
            println!("no value");
        },
    }
   let temp = convert(some1);

}
//注意使用match时,需要穷举所有可能性
fn convert(x: Option<i32>) -> Option<i32>{
    match x {
        None => None,
        Some(i) => Some(i+1),
    }
}
fn convert2(x: Option<i32>) -> Option<i32>{
    match x {
        Some(i) => Some(i+1),
        _ => None, //通配符,类似else
    }
}
//输出
//find
//option 中的值是 1