Struct trong Rust
TIL
719
Rust
28
programming
80
White

Đào An viết ngày 24/01/2019

Giới thiệu

  • Struct là một kiểu dữ liệu, nó cho phép chúng ta kết hợp các dữ liệu khác kiểu và/hoặc cùng kiểu nhau để tạo thành một kiểu dữ liệu mới.
  • Có 3 loại struct chính trong Rust là: named-field, tuple-like, và unit-like.
  • Chương này chúng ta sẽ tìm hiểu cách sử dụng của các loại struct trong Rust.

Named-Field Structs

Cú pháp:

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

  • Ở bên trên chúng ta đã định nghĩa 1 struct User, có 4 trường là username, email, sign_in_count và active , chúng có các kiểu dữ liệu tương ứng là String, String, u64 và bool.
  • Để sử dụng một struct sau khi định nghĩa, chúng ta cần khởi tạo 1 instance của nó.
let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
  • Để truy cập vào 1 trường của instance ta sử dụng . operator.
user1.email = String::from("anotheremail@example.com");
  • Mặc định các trường của struct và struct là private, do đó để truy cập chúng bên ngoài module định nghĩa chúng, ta cần thêm từ khóa pub trước trường và struct.
pub struct User { // khai báo public cho struct
    pub username: String, // username có thể đc truy cập bên ngoài module
    email: String, // ko thể truy cập từ bên ngoài module.
    sign_in_count: u64,
    active: bool,
}
// * Cú pháp tạo 1 instance bằng cách update các trường của 1 instance khác.
let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};

  • Ở đây các trường email, username của user2 sẽ đc cập nhật mới, các trường còn lại sẽ giữ nguyên như user1.

Tuple-Like Structs

Cú pháp

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let Color(zero, one, two) = Color(0, 1, 2);
let origin = Point(0, 1, 2);

assert_eq!(zero , origin.0);
assert_eq!(one , origin.1);
assert_eq!(two , origin.2);
  • Tuple-Like Structs ko khác gì với tuple thường, ngoại trừ nó có tên riêng.

Unit-Like Structs

// cú pháp chỉ là 2 dấu () ko chứa bất kì trường nào
()
  • Unit-like struct được sử dụng khi implement 1 trait.

Định nghĩa phương thức (method) với impl

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}
  • Bên trên chúng ta định nghĩa method area của struct Rectangle. Để gọi method từ instance thì ta cũng sử dụng . operator như các ngôn ngữ khác.
  • Nếu muốn đọc dữ liệu từ instance thì tham số đầu tiên của method phải là self hoặc &self. Nếu muốn đọc và thay đổi dữ liệu từ instance thì tham số đầu tiên là &mut self.
  • Sự khác nhau giữa self&self :
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn get(self) -> (u32, u32) {
        (self.width, self.height)
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("{:?}", rect1);
    let (width, height) = rect1.get();
    println!("{:?}", rect1); // lỗi do giá trị width và height
  \\ của instance
 \\ đã đc move đến biến width, height bên ngoài. rect1 trở thành uninitialized. 
}
//////// Sử dụng &self
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn get(&self) -> (u32, u32) {
        (self.width, self.height)
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("{:?}", rect1);
    let (width, height) = rect1.get();
    println!("{:?}", rect1); // Rectangle { width: 30, height: 50 } -> Ok
}
  • Do vậy nên ta thường sử dụng &self hơn là sử dụng self
  • Method ko có từ khóa self ở tham số đầu tiên được gọi là static method -> ko đọc/ ghi được dữ liệu của instance. Chúng ta thường dùng static method như 1 constructor trong Rust.
impl Rectangle {
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}
let sq = Rectangle::square(3);

Generic Structs

pub struct Queue<T> {
    older: Vec<T>,
    younger: Vec<T>
}

// implement method
impl<T> Queue<T> {
    pub fn new() -> Queue<T> { // -> Self
        Queue { older: Vec::new(), younger: Vec::new() }
    }
    pub fn push(&mut self, t: T) {
        self.younger.push(t);
    }
    pub fn is_empty(&self) -> bool {
        self.older.is_empty() && self.younger.is_empty()
    }
}

fn main() {
    let mut q = Queue::<char>::new(); // khai báo kiểu dữ liệu T, cú pháp ::<T>
    let mut r = Queue::new(); // rust tự suy ra kiểu dữ liệu T
    q.push('C'); 
    r.push(0.74); 
    q.push('A'); 
    r.push(2737.7); 
}

Structs với Lifetime Parameters

struct Extrema<'elt> {
    greatest: &'elt i32,
    least: &'elt i32,
}

fn find_extrema<'s>(slice: &'s [i32]) -> Extrema<'s> {
    let mut greatest = &slice[0];
    let mut least = &slice[0];
    for i in 1..slice.len() {
        if slice[i] < *least { least = &slice[i]; }
        if slice[i] > *greatest { greatest = &slice[i]; }
    }
    Extrema { greatest, least }
}

fn main() {
    let a = [0, -3, 0, 15, 48];
    let e = find_extrema(&a);
    assert_eq!(*e.least, -3);
    assert_eq!(*e.greatest, 48);
}
  • Ở code bên trên chúng ta có thể khai báo function ko có lifetime vì return type và argument có cùng lifetime.
fn find_extrema(slice: &[i32]) -> Extrema {

Sử dụng Derive attribute để implement 1 số traits thông dụng.

#[derive(Copy, Clone, Debug, PartialEq, PartialCmp)]
struct Point {
    x: f64,
    y: f64
}
Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Đào An

4 bài viết.
2 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
1 0
Setup Cài đặt Meteor OSX/Linux curl https://install.meteor.com/ | sh Window https://install.meteor.com/windows Khởi tạo project Meteor meteor ...
Đào An viết hơn 2 năm trước
1 0
White
1 1
TNgày 8/12/2018 Bài này m viết lưu trữ để sau này cài lại đỡ phải mò. Cầu hình máy đã cài: CPU Intel Core i5 8600K 3.6Ghz Turbo Up to 4.3Ghz / 9...
Đào An viết 10 tháng trước
1 1
White
1 0
Basic Types In Kotlin, everything is an object. Numbers Types: Double, Float, Long, Int, Short, Byte Tags: Long (L), Float (f, F) 123.5f ...
Đào An viết 9 tháng trước
1 0
Bài viết liên quan
White
55 23
Luận về comment code (Phong cách kiếm hiệp) Comment code luôn là vấn đề gây tranh cãi sứt đầu mẻ trán trong giới võ lâm. Xưa kia, thuở còn mài đít...
Huy Hoàng Phạm viết gần 4 năm trước
55 23
White
16 0
Không gì đẹp bằng nụ cười khi đôi mắt e lệ nhìn xuống. Victor Hugo Các bạn có thể đọc bài viết gốc tại (Link) Tò mò khi tìm hiểu hoạt động của ...
Đào Văn Hùng viết gần 2 năm trước
16 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
4 bài viết.
2 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!