21

Là một nhà phát triển, thật dễ dàng để nhảy vào chuyến tàu cường điệu và cố gắng học hoặc thậm chí sử dụng trong các dự án thú cưng các thư viện, khuôn khổ mới nhất và tại sao không phải là ngôn ngữ lập trình. Trong một lĩnh vực mà mọi thứ đều phát triển với tốc độ rất cao, đôi khi rất khó để giữ được sự tập trung và không trở nên điên cuồng với những thay đổi liên tục. Trong trường hợp của tôi, tôi thích đọc và thực hành các ngôn ngữ lập trình khác nhau và càng nhiều càng tốt, bởi vì chúng mang lại những tầm nhìn khác nhau về cách giải quyết vấn đề và thậm chí cung cấp cho bạn nhiều công cụ hơn cho bạn hàng ngày. 

Và bài viết hôm nay nói về việc khám phá Rust.

Tại sao gỉ?

Trong một buổi Ăn trưa & Học hỏi mà chúng tôi thực hiện tại Apiumhub , một đồng nghiệp đã đưa cho tôi ý tưởng chuyển một khách hàng nội bộ mà chúng tôi có bằng ngôn ngữ thuần túy sang một số ngôn ngữ khác và vì các ứng cử viên là Go và Rust, vì giữa chúng tôi không đồng ý, chúng tôi quyết định rằng mỗi bên sẽ chọn một ngôn ngữ và tạo cổng của nó.

Kết quả là ứng dụng đó không bao giờ di chuyển, nhưng trên đường đi, cả hai chúng tôi đều có thể khám phá ra những ưu điểm và nhược điểm của các ngôn ngữ như GO và Rust.

Kể từ thời điểm đó, tôi đã bị cuốn vào Rust và tuyệt vọng kể từ đó, bất kỳ dự án cá nhân hoặc bằng chứng về khái niệm hoặc ý tưởng mà tôi có thể nghĩ ra, tôi cố gắng đi trước với Rust.

Rust là gì?

Rust dựa trên ba trụ cột:

  • Hiệu suất , nhanh chóng và hiệu quả với bộ nhớ, không có thời gian chạy hoặc bộ thu gom rác.
  • Độ tin cậy , mô hình sở hữu đảm bảo an toàn bộ nhớ và an toàn luồng.
  • Năng suất , tài liệu tuyệt vời, trình biên dịch trong hầu hết các trường hợp cho bạn biết cách thực hiện và cung cấp cho bạn tài liệu tham khảo để bạn hiểu vấn đề và một công cụ phục vụ như một trình quản lý gói, định dạng mã, cải tiến và đề xuất.

Rust bắt đầu bằng cách tự định nghĩa mình là một ngôn ngữ hệ thống, nhưng theo thời gian thì định nghĩa đó đã biến mất, ngày càng có nhiều thư viện cho web ,   GUI , trò chơi và tất nhiên là cho các hệ thống!

Điều đầu tiên bạn nghĩ khi đọc “ngôn ngữ hệ thống” là… tôi sẽ phải xử lý các con trỏ, tôi sẽ phải giải phóng và gán bộ nhớ, tôi sẽ phải làm việc ở mức rất thấp mà không cần trừu tượng và tất nhiên… nếu nó không phải là ngày của bạn vì việc quay trở lại nguồn gốc của C C ++ là điều đáng sợ, nhưng phần lớn những nỗi sợ hãi này đã được giải quyết rất tốt và bằng trình biên dịch! mà nó tạo điều kiện thuận lợi cho chúng tôi rất nhiều.

Trong bài viết này, chúng ta sẽ thấy một số khái niệm cơ bản về gỉ và một số tính năng của nó mà theo quan điểm của tôi, nó trở thành một ngôn ngữ rất hấp dẫn.

Khái niệm rỉ sét

  • Rust có nhiều loại nguyên thủy
  • Rust đặt cược vào tính bất biến, do đó, tất cả các biến được khai báo là bất biến trừ khi chúng được chỉ định bằng từ khóa mut tại thời điểm khai báo.
  • Điều tương tự cũng xảy ra với khả năng hiển thị, mọi thứ đều riêng tư và trong trường hợp bạn muốn công khai, bạn sẽ làm điều đó với từ khóa pub.
  • Trong trường hợp các hàm, chúng ta có thể chỉ định từ khóa trả về để chỉ ra rằng đó là giá trị được trả về từ hàm hoặc nếu câu cuối cùng không bao gồm; nó sẽ trở thành giá trị trả về của hàm.
  • Rust có một kiểu suy luận rất đầy đủ và hiếm khi chúng ta cần chỉ định loại biến chúng ta đang tạo.
  • Các tính năng khác mang lại cho Rust một điểm cộng là Kiểu chung, Đối sánh mẫu, Hệ thống Macro và nhiều khái niệm về lập trình hàm như hàm hạng nhất, bao đóng, Trình lặp
let name = "Jon".to_string(); // String type
let year = 2020; // i32 type
let age: u8 = 35;

let mut index = 0; //mutable variable
index = index +=1; 

let add_one = |x: i32| x + 1; //closure
let two = add_one(1);

let numbers = vec![1, 2, 3, 4, 5, 6];
let pairs: Vec = numbers.into_iter()
        .filter(|n| n % 2 == 0)
        .collect(); // [2, 4, 6]

fn greet(name: String) {
    println!("hello {}", name);
}
pub fn plus_one(x: i32) -> i32 {
    return x + 1; 
}
pub fn plus_two(x: i32) -> i32 {
    x + 2 
}

Quyền sở hữu, vay mượn và thời gian tồn tại

Ba khái niệm này là độ phức tạp lớn nhất mà chúng ta sẽ tìm thấy trong Rust, vì chúng là những khái niệm mà trong ngôn ngữ có QA, chính QA sẽ xử lý chúng để làm cho nó trở nên minh bạch cho nhà phát triển.

Vì nó không có thời gian chạy liên kết hoặc Trình thu gom rác để giải phóng bộ nhớ của các đối tượng mà nó không sử dụng, tất cả điều này được trình biên dịch xử lý với sự trợ giúp của quyền sở hữu,
Mặc dù khái niệm này phù hợp với nhiều bài viết, chúng ta hãy xem những điều cơ bản của khái niệm với một số ví dụ.

Mỗi giá trị có một biến được chỉ định (chủ sở hữu) và chỉ có thể có một chủ sở hữu tại một thời điểm, khi chủ sở hữu đó nằm ngoài phạm vi, giá trị sẽ được giải phóng.

Vì vậy, chúng tôi có ví dụ sau:

fn main() {
    let name = "Jon".to_string();
    greet(name);
    println!("goodbye {}", name); //^^^^ value borrowed here after move
}

fn greet(name:String) {
    println!("hello {}", name);
}

Trình biên dịch cho chúng ta biết rằng chủ sở hữu của tên biến đã được chuyển cho hàm chào, vì vậy sau khi chạy chào, nó không còn trong phạm vi đó nữa. Để giải quyết nó đơn giản như chỉ ra rằng những gì chúng tôi muốn là cho chủ sở hữu mượn, để khi chức năng kết thúc, lấy lại chủ sở hữu và điều đó được chỉ ra bằng &.

fn main() {
    let name = "Jon".to_string();
    greet(&name);
    println!("goodbye {}", name);
}

fn greet(name:&String) {
    println!("hello {}", name);
}

Vòng đời là kiểm tra việc quản lý quyền sở hữu và vay mượn các giá trị, hầu hết các trường hợp trình biên dịch biết cách diễn giải nó, nhưng đôi khi cần phải chi tiết hóa nó. Không đi vào quá nhiều chi tiết vì cũng giống như quyền sở hữu và vay mượn, cho một loạt các bài báo.

Cấu trúc

Các cấu trúc tồn tại để xác định các loại của riêng chúng ta, chúng được tạo bằng cấu trúc từ khóa và không có hành vi liên quan.

Để cung cấp hành vi cho một cấu trúc, nó sẽ được thực hiện với từ khóa impl.


struct Point {
    x: f32,
    y: f32,
}
impl Point {
    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}
let point1 = Point {
  x: 10.0,
  y: 20.0,
};

let point2 = Point {
  x: 5.0,
  y: 1.0,
};

let point3 = point1.add(point2); //Point { x: 15.0, y: 21.0 }

Trong triển khai Point, phương thức add nhận được dưới dạng tham số tự, điều này là do phương thức đó là ví dụ, nếu chúng ta không muốn thực hiện nó, nó đơn giản như loại bỏ bản thân

Đặc điểm

Rust Traits là một tập hợp các phương thức được định nghĩa để thực hiện bởi Structs, chúng tương tự như các giao diện của các ngôn ngữ khác.

pub trait Summary {
    fn summarize(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

Enums

Chúng ta có thể tạo các enum, không có giá trị, có giá trị hoặc thậm chí mỗi enum có các giá trị thuộc các kiểu khác nhau.

enum IpAddrKind {
    V4,
    V6,
}

enum IpAddr {
    V4(String),
    V6(String),
}

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

Đây là nơi mà việc đối sánh mẫu và cấu trúc lại đóng một vai trò rất quan trọng trong việc quản lý môi trường

Bí danh

Trong Rust, chúng tôi có thể tạo bí danh của mình cho các loại hiện có.

type Second = u64;
let seconds: Second = 10;

Thêm chức năng cho các lớp sau khi chúng được xác định

Trong một số ngôn ngữ lập trình, có thể thêm các phương thức (phương thức mở rộng) vào các lớp khi chúng đã được định nghĩa, trong Rust điều này sẽ không ít! Đầu tiên, chúng ta sẽ tạo đường dẫn với phương thức mà chúng ta muốn sử dụng, sau đó chúng ta sẽ triển khai đường dẫn đã tạo trước đó thành kiểu mà chúng ta muốn mở rộng.

pub trait Reversible {
    fn reverse(&self) -> Self;
}

impl Reversible for String {
    fn reverse(&self) -> Self {
        self.chars()
            .rev()
            .collect::()
    }
}

let hello = String::from("hello");
println!("{}",hello.reverse()); // olleh

Người vận hành quá tải

Hãy tưởng tượng bạn có thể áp dụng các phép toán số học cho các kiểu của riêng bạn, theo ví dụ trước điểm cấu trúc, có thể thêm Điểm bằng toán tử + đơn giản. Trong Rust, điều này có thể thực hiện được bằng cách nạp chồng các toán tử, toán tử này giống nhau một lần nữa, triển khai các đặc điểm cho các kiểu. Đây là tất cả các toán tử có thể để quá tải .

struct Point {
    x: f32,
    y: f32,
}

impl std::ops::Add for Point { // implement Add trait for Point
    type Output = Self;

    fn add(self, other: Self) -> Self { //implement add function
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

let point1 = Point { x: 10.0, y: 20.0};

let point2 = Point {x: 5.0, y: 1.0};

let p = point1 + point2; // apply add trait

Toán tử Dấu hỏi

Rất thường thấy việc xử lý lỗi trong Rust thông qua kiểu Kết quả là T giá trị của OK và E là một trong những lỗi, và việc xử lý kiểu này được thực hiện thông qua đối sánh mẫu. Hãy tưởng tượng rằng chúng ta muốn đọc nội dung của một tệp. Đối với nó, chúng ta sẽ sử dụng hàm read_to_string của module fs, kết quả của hàm này là Result .


let content = fs::read_to_string("filename");
match content {
    Ok(file_content) => { println!("{}", file_content) }
    Err(e) => { println!("Error reading file: {}", e) }
}

Bằng cách đối sánh mẫu, chúng tôi đã xử lý cả hai trường hợp có thể xảy ra của kết quả. Đối với ví dụ này, chúng tôi chỉ muốn in nó bằng bảng điều khiển, nhưng hãy tưởng tượng rằng bạn muốn xử lý nội dung đó, mã trở nên phức tạp hơn một chút, đối với những trường hợp này trong Rust có ?toán tử mà chúng tôi trực tiếp lấy giá trị của Kết quả nếu nó diễn ra tốt và nếu không trực tiếp thì lỗi sẽ được trả về dưới dạng trả về của hàm. Nhưng để sử dụng ?toán tử, chữ ký phương thức phải trả về một kiểu Kết quả


fn get_content() ->  Result<string, error="">{
    let content = fs::read_to_string("filename")?;
    println!("{}", content);
    Ok(content)
}</string,>

Nếu quá trình đọc tệp không thành công, nó sẽ tự động trả về Dấu vết lỗi, nếu không, mã sẽ tiếp tục được thực thi cho đến khi trả về Kết quả ok của nội dung.

Chuyển đổi loại

Một tính năng rất thú vị khác là chuyển đổi kiểu có thể được áp dụng trong Rust chỉ bằng cách triển khai Đặc điểm std::convert::From.

Trường hợp sử dụng rõ ràng nhất là một hàm trong đó bạn xử lý các loại lỗi khác nhau nhưng việc trả về hàm mà bạn muốn trong trường hợp lỗi là lỗi của bạn, của miền của bạn, thông qua đối sánh mẫu, chúng tôi có thể tìm kiếm tất cả các kết quả và tạo ra các Kết quả thuộc loại của chúng tôi, nhưng nó sẽ làm cho mã của chúng tôi khó duy trì và không dễ đọc.

Sử dụng ?toán tử và chuyển đổi kiểu sẽ giống như sau:

fn get_and_save() -> Result<string, domainerror=""> {
    let content:  Result<string,httperror> = get_from_http()?; 
    let result: Result<string,dberror> = save_to_database(content)?; 
      // with ? operator in case of error, the return of the function will be Result of Error
    Ok(result)
}

pub struct DomainError {
    pub error: String,
}

impl std::convert::From for DomainError {
    fn from(_: DbError) -> Self {
        DomainError {
            error: (format!("Error connecting with database")),
        }
    }
}

impl std::convert::From for DomainError {
    fn from(_: HttpError) -> Self {
        DomainError {
            error: (format!("Error connecting with http service")),
        }
    }
}</string,dberror></string,httperror></string,>

Hàng hóa & Tiện ích

Và nếu chúng ta nói về Rust, chúng ta không thể bỏ qua vị trí quản lý gói của bạn, đi kèm với bản cài đặt Rust.

Với hàng hóa, chúng ta có thể tạo một dự án từ đầu, quản lý các phụ thuộc, tạo bản phát hành, khởi chạy các bài kiểm tra, tạo tài liệu, xuất bản gói lên sổ đăng ký.

Ngoài ra, có một danh sách lớn các lệnh của bên thứ ba có sẵn .

Tài nguyên

Mặc dù Rust được tạo ra bởi Mozilla, Rust vẫn được duy trì bởi cộng đồng và chính cộng đồng là người đề xuất những thay đổi và điều chỉnh ngôn ngữ cho phù hợp với nhu cầu.

Một số liên kết thú vị nhất cần theo dõi để cập nhật tin tức:

  • gỉ-lang.slack : Slack trong đó tất cả các vấn đề ngôn ngữ được thảo luận với rất nhiều sự trợ giúp cho những người mới làm quen với ngôn ngữ này.
  • Hàng tuần : Bản tin hàng tuần với các tin tức về thay đổi ngôn ngữ, các bài báo và hội nghị / tọa đàm thú vị.
  • Youtube : kênh chính thức của Rust nơi các hội nghị, cuộc họp của các nhóm làm việc khác nhau được thành lập để phát triển ngôn ngữ được đăng tải.
  • Discord : Máy chủ Discord nơi hầu hết các nhóm làm việc được điều phối để duy trì ngôn ngữ.
  • Sách Rust : Tài liệu chính thức về Rust, mọi thứ bạn cần biết về ngôn ngữ này đều có trong sách.

Và một vài dự án cá nhân mà tôi đang áp dụng vào tất cả những gì tôi đang đọc về Rust

  • Adh : là một ứng dụng khách Docker, được chuyển từ ApiumHub ban đầu với các lệnh mà tôi sử dụng nhiều nhất trong cuộc sống hàng ngày, vẫn còn nhiều tính năng cần được bổ sung.
  • COVID-bot : là một bot điện tín được phát triển trên Rust để theo dõi COVID-19
|