Structures in Rust

Column introduction: This column is an introductory article about the Rust language. The purpose is to share programming skills and knowledge about the Rust language. As for the Rust language, although it does not have a long history like C++ or Python, it can be said to have many advantages. It not only inherits the running speed of C++, but also has the memory management of Java. As far as I am concerned, there is another advantage. It is the integrated compilation tool cargo. The statement style is very similar to C++, so I still prefer this language. I hereby create this column to share as a record of learning.

Daily sharing: Work hard every day, not for anything else, just so that you can have more choices in the future, choose comfortable days, and choose the people you like!


Definition and instantiation of structures

Like the c++/c language, the Rust language also has structures. Like tuples, the variable data types in the structure can be different, and only reference characters are needed to get the data.

struct Buffer{
  length:usize,
  width:usize,
  flag:bool,
  name:String,
}

fn main() 
{
  let mut buffer = Buffer{
    length:90,
    width:100,
    flag:true,
    name:String::from("test"),
  }; 
  println!("{}", buffer.length);
}

In the data structure, the c/c++ language can use the structure data type to define functions as the return value type of the function. In Rust, it can also be used as the return type of the function.

fn return_Buffer(length:usize,flag:bool)->Buffer {
  Buffer{
    length:length,
    width:100,
    flag:flag,
    name:String::from("test"),
  }
}

 The function here returns the structure type, but fields such as length and flag are repeatedly written. You can use field initialization abbreviation syntax, that is, you do not need to write specific variable values, only the field names need to be written, but the premise is that the parameters and field names are the same. of.

fn return_Buffer(length:usize,flag:bool)->Buffer {
  Buffer{
    length,
    width:100,
    flag,
    name:String::from("test"),
  }
}

Structure update syntax

struct Buffer{
  length:usize,
  width:usize,
  flag:bool,
  name:String,
}

fn main() 
{
  let mut buffer = Buffer{
    length:90,
    width:100,
    flag:true,
    name:String::from("test"),
  }; 
  let mut buffer_two=Buffer{
    length:buffer.length,
    width:50,
    flag:false,
    name:buffer.name,
  };
  let mut buffer_three = Buffer{
    flag:true,
    ..buffer_two
  };
  println!("{}", buffer.length);

}
fn return_Buffer(length:usize,flag:bool)->Buffer {
  Buffer{
    length,
    width:100,
    flag,
    name:String::from("test"),
  }
}

The above example refers to using other structure variables to create a new structure variable. Although the code looks relatively simple, there is a lot of knowledge involved. For example, if a variable of String data type is defined in the Buffer structure, then after we use buffer to create buffer_two, the buffer will lose its function. This has been mentioned in the previous chapter on data types. In the same way, when creating the buffer_three variable, we first define the value of the flag field, and then use the buffer_two variable for all remaining fields. Since the name field is also used, the buffer_two variable loses its effect, but if we only use other fields, is still valid. as follows:

  let mut buffer_three = Buffer{
    name:String::from("alice"),
    ..buffer_two
  };
  println!("{}",buffer_two.name);

Let me state here that although the buffer has lost its role, it only means that the variable no longer has a role, but the non-string type fields in it still have a role, because they are already variables themselves.

Create different types using tuple structs without named fields

Tuple structure uses tuples to define the structure, or in other words, the structure is defined in the form of tuples.

struct Bufferlines(i32,i32,i32);
struct Bufferline(u32,u32,u32);
let mut buffer_fine=Bufferline(32,34,45);
  let mut buffer_fine_two = Bufferlines(32,34,45);
  println!("{}",buffer_fine.1);

Cell-like structure without any fields

In the Rust language, there is a structure called a unit-like structure . In fact, this roughly means defining a structure, but it does not contain any data types, which is equivalent to an empty shell.

struct Bufferclong; //定义一个类单元结构体
let mut buffer_four=Bufferclong; //定义一个类单元结构体变量。

Structure example program

Structures can be used in many aspects. Structures are used in the study of data structures in C language. The practicality of structures is that they can store variables of many data types, making the code brief and enhancing the code. Integrity.

//定义一个结构体
struct Rectangle
{
  width: usize,
  height: usize,
}

fn main(){
  let mut rect = Rectangle{
    width: 30,
    height: 50,
  };
  println!("The area is {}",area(&rect));

}
fn area(rect: &Rectangle) ->usize { 
  return rect.width * rect.height;  //如果不使用return关键字,则不需要分号
}

Here we define a structure, define two fields, width and height, useize when defining the type (it can run on either 32-bit or 64-bit computers), then create an entity and assign values ​​to the fields. Then call the already defined area function. It should be noted here that when defining a function, the parameters are reference types of the structure. This reason is related to the ownership attribute explained earlier. If we do not use references, the structure instance object originally defined after passing parameters can no longer be used. So the reference used here is also to continue to use the object later.

Add practical functions by deriving traits

When we use the println!() macro, although we can output most of the data content, we cannot directly output the structure entity object. So is there any way?

Let's first take a look at what errors will be reported when using println!() .

`Rectangle` doesn't implement `std::fmt::Display`
  --> src/main.rs:14:17
   |
14 |   println!("{}",rect);
   |                 ^^^^ `Rectangle` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `Rectangle`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

In the above error report, we can see that the error report provides a solution. Let’s try to use the solution provided by the error report:

println!("{:#?}",rect);
   |                    ^^^^ `Rectangle` cannot be formatted using `{:?}`

We found that an error was still reported, but the error message gave a message and added a Debug.

//定义一个结构体
#[derive(Debug)]
struct Rectangle
{
  width: usize,
  height: usize,
}

fn main(){
  let mut rect = Rectangle{
    width: 30,
    height: 50,
  };
  println!("The area is {}",area(&rect));
  println!("{:#?}",rect);

}
fn area(rect: &Rectangle) ->usize { 
  return rect.width * rect.height;  //如果不使用return关键字,则不需要分号
}

Through the display code added above, we can already print out the structure. So is there any other simple method?

dbg!macro

dbg! The difference between macro and println! macro is that dbg! The macro accepts ownership of the expression, while println! Quotes are accepted. If you don’t understand this, look at an example below.

//定义一个结构体
#[derive(Debug)]
struct Rectangle
{
  width: usize,
  height: usize,
}

fn main(){
  let mut rect = Rectangle{
    width: 30,
    height: 50,
  };
  println!("The area is {}",area(&rect));
  println!("{:#?}",rect); //第一次打印
  println!("{:?}",rect);//第二次使用println!打印
  //使用dbg!打印
  dbg!(rect); //第一次打印
  dbg!(rect);//第二次打印,此时运行错误,rect已经便不再具有所有权。


}
fn area(rect: &Rectangle) ->usize { 
  return rect.width * rect.height;  //如果不使用return关键字,则不需要分号
}

Use println above! Macros can be printed continuously, but using dbg! The macro can only print once, after which the variable no longer has ownership. Ownership has been transferred. Therefore, an error will appear when running the above code.

let mut rect = Rectangle{    | -------- move occurs because `rect` has type `Rectangle`, which does not implement the `Copy` trait ... 18 | dbg!(rect); //Chapter Print once    | ---------- value moved here 19 | dbg!(rect);//Printing for the second time, an error occurs and rect no longer has ownership.    | ^^^^ value used here after move





 If you don't want dbg! Get ownership of the expression, then call dbg! When passing reference parameters. Such as dbg!(&rect);

impl syntax

The area function we defined earlier needs to pass parameters if it needs to be used. The important thing is that many of the functions we define may not call structure variables, but when we use functions related to structures, it will be very troublesome. In order to solve this trouble, Rust introduced the impl syntax.

Define method

Let’s look at an example first:

//定义一个结构体
#[derive(Debug)]
struct Rectangle
{
  width: usize,
  height: usize,
}
impl Rectangle {
  fn area(&self) ->usize { 
    return self.width * self.height;  //如果不使用return关键字,则不需要分号
  }
}

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

}

 In the above code, we use impl to define a block, and everything in this block will be associated with the Rectangle type. The parameter uses &self, which is used to replace rectangle:&Rectangle. This means that we can use properties from struct instances. For every function associated with a structure, the first parameter must be &self, and subsequent parameters can be added according to your needs.

Automatic referencing and dereferencing in Rust:

There are dereferences and references in C/C++. I believe many friends who are familiar with C++ know these two concepts, so I won’t introduce them in detail here.

This complex mechanism has been canceled in Rust, which means we don't need to consider whether dereference is needed, we can just use the attribute operator directly.

 multiple parameters

//定义一个结构体
#[derive(Debug)]
struct Rectangle
{
  width: usize,
  height: usize,
}
impl Rectangle {
  fn area(&self) ->usize { 
    return self.width * self.height;  //如果不使用return关键字,则不需要分号
  }
  fn hold(&self,other: &Rectangle) -> bool {
    self.width > other.width && self.height > other.height
  }
}

fn main(){
  let mut rect = Rectangle{
    width: 30,
    height: 50,
  };
  let mut rect2 = Rectangle{
    width:40,
    height:50,
  };
  let mut rect3 = Rectangle{
    width:20,
    height:30,
  };
  println!("{}", rect.hold(&rect2));
  println!("{}", rect2.hold(&rect3));

}

Many people may not understand what the above code means. In fact, a simple look is that a function with a comparative length and width is defined in the impl block, and what is more obvious is that there is one more parameter (other:&Rectangle) , which means we are using another Rectangle instance instead of a structure instance. So what if we want a few more parameters that are not structure instances?

 fn get_v(&self,length:usize) -> usize {
    self.width * self.height*length
  }

By adding the above code in the impl block, you can get the volume of the cuboid. The newly added parameter here uses the usize type. Why not use other?

Rules for setting multiple parameters of functions in impl blocks:

1. If you want to use multiple parameters, the first parameter must be &self.

2. If you want to use different instances of the same structure type, you need to add other to distinguish them.

3. If you only add ordinary parameters, you can add them directly later.

correlation function

In the official definition, all functions in the impl block are called associated functions. As we said earlier, if you want to define an associated function of a structure, the first parameter must be &self, but we can also not use &self. As the first parameter, but this is no longer a method and cannot act on instances of the structure.

Relevant functions that are not methods are often used as constructors that return a new instance of a structure. The name of these functions is usually newbut newis not a keyword.

For example:

impl Rectangle{
  fn new(size:usize,length:usize)->Self{
    Self{
      width:size,
      height:length,
    }
  }
}

Then call it in the main function:

let mut rects = Rectangle::new(34,45);

println!("{}", rects.area());

The calling method here is no longer to use an instance to call, but to use:: to call. This is because the function is only established in the namespace of the structure without obtaining an instance, so it needs to be called using::. Later Will explain in detail.

Multiple impl blocks

In the Rust language, a structure is allowed to have multiple impl blocks, just like the above code. Regarding this performance, I will explain it later when needed. Beginners only need guidance. The following is the content of this section. All the codes, if you know something about this section, you can take a closer look.

//定义一个结构体
#[derive(Debug)]
struct Rectangle
{
  width: usize,
  height: usize,
}
impl Rectangle {
  fn area(&self) ->usize { 
    return self.width * self.height;  //如果不使用return关键字,则不需要分号
  }
  fn get_v(&self,length:usize) -> usize {
    self.width * self.height*length
  }
  fn hold(&self,other: &Rectangle) -> bool {
    self.width > other.width && self.height > other.height
  }
}

impl Rectangle{
  fn new(size:usize,length:usize)->Self{  //相当于是结构体的构造函数
    Self{
      width:size,
      height:length,
    }
  }
}
fn main(){
  let mut rects = Rectangle::new(34,45);
  println!("{}", rects.area());

  let mut rect = Rectangle{
    width: 30,
    height: 50,
  };
  let mut rect2 = Rectangle{
    width:40,
    height:50,
  };
  let mut rect3 = Rectangle{
    width:20,
    height:30,
  };
  println!("{}", rect.hold(&rect2));
  println!("{}", rect2.hold(&rect3));
  println!("The rect2 体积是:{}",rect2.get_v(20));

}

Summarize

The content of this section is mainly to explain the relevant knowledge in structures. Through structures, we can connect related data fragments and name them, which can make the code clearer. In impla block, you can define functions that are associated with your type, and a method is an associated function that lets you specify the behavior that an instance of the structure will have.

 

おすすめ

転載: blog.csdn.net/qq_59931372/article/details/133135998