国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Rust編程語言入門之Rust的面向對象編程特性

這篇具有很好參考價值的文章主要介紹了Rust編程語言入門之Rust的面向對象編程特性。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Rust 的面向對象編程特性

一、面向對象語言的特性

Rust是面向對象編程語言嗎?

  • Rust 受到多種編程范式的影響,包括面向對象
  • 面向對象通常包含以下特性:命名對象、封裝、繼承

對象包含數據和行為

  • “設計模式四人幫”在《設計模型》中給面向對象的定義:
    • 面向對象的程序由對象組成
    • 對象包裝了數據和操作這些數據的過程,這些過程通常被稱作方法或操作
  • 基于此定義:Rust是面向對象的
    • struct、enum 包含數據
    • impl 塊為之提供了方法
    • 但帶有方法的 struct、enum 并沒有被稱為對象

封裝

  • 封裝:調用對象外部的代碼無法直接訪問對象內部的實現細節(jié),唯一可以與對象進行交互的方法就是通過它公開的 API
  • Rust:pub 關鍵字
pub struct AveragedCollection {
  list: Vec<i32>,
  average: f64,
}

impl AveragedCollection {
  pub fn add(&mut self, value: i32) {
    self.list.push(value);
    self.update_average();
  }
  
  pub fn remove(&mut self) -> Option<i32> {
    let result = self.list.pop();
    match result {
      Some(value) => {
        self.update_average();
        Some(value)
      },
      None => None,
    }
  }
  
  pub fn average(&self) -> f64 {
    self.average
  }
  
  fn update_average(&mut self) {
    let total: i32 = self.list.iter().sum();
    self.average = total as f64 / self.list.len() as f64;
  }
}

繼承

  • 繼承:使對象可以沿用另外一個對象的數據和行為,且無需重復定義相關代碼
  • Rust:沒有繼承
  • 使用繼承的原因:
    • 代碼復用
      • Rust:默認 trait 方法來進行代碼共享
    • 多態(tài)
      • Rust:泛型和 trait 約束(限定參數化多態(tài) bounded parametric)
  • 很多新語言都不使用繼承作為內置的程序設計方案了。

二、使用 trait 對象來存儲不同類型的值

有這樣一個需求

  • 創(chuàng)建一個 GUI 工具:
    • 它會遍歷某個元素的列表,依次調用元素的 draw 方法進行繪制
    • 例如:Button、TextField 等元素
  • 在面向對象語言里:
    • 定義一個 Component 父類,里面定義了 draw 方法
    • 定義 Button、TextField 等類,繼承與 Component 類

為共有行為定義一個 trait

  • Rust 避免將 struct 或 enum 稱為對象,因為他們與 impl 塊是分開的
  • trait 對象有些類似于其它語言中的對象:
    • 它們某種程度上組合了數據與行為
  • trait 對象與傳統(tǒng)對象不同的地方:
    • 無法為 trait 對象添加數據
  • trait 對象被專門用于抽象某些共有行為,它沒其它語言中的對象那么通用

Trait 動態(tài) lib.rs 文件

pub trait Draw {
  fn draw(&self);
}

pub struct Screen {
  pub components: Vec<Boc<dyn Draw>>,
}

impl Screen {
  pub fn run(&self) {
    for component in self.components.iter() {
      component.draw();
    }
  }
}

pub struct Button {
  pub width: u32,
  pub height: u32,
  pub label: String,
}

impl Draw for Button {
  fn draw(&self) {
    // 繪制一個按鈕
  }
}

泛型的實現 一次只能實現一個類型

pub struct Screen<T: Draw> {
  pub components: Vec<T>,
}

impl<T> Screen<T>
where
	T: Draw,
{
  pub fn run(&self) {
    for component in self.components.iter() {
      component.draw()
    }
  }
}

main.rs 文件

use oo::Draw;
use oo::{Button, Screen};

struct SelectBox {
  width: u32,
  height: u32,
  options: Vec<String>,
}

impl Draw for SelectBox {
  fn draw(&self) {
    // 繪制一個選擇框
  }
}

fn main() {
  let screen = Screen {
    components: vec![
      Box::new(SelectBox {
        width: 75,
        height: 10,
        options: vec![
          String::from("Yes"),
          String::from("Maybe"),
          String::from("No"),
        ],
      }),
      Box::new(Button {
        width: 50,
        height: 10,
        label: String::from("OK"),
      }),
    ],
  };
  
  screen.run();
}

Trait 對象執(zhí)行的是動態(tài)派發(fā)

  • 將 trait 約束作用于泛型時,Rust編譯器會執(zhí)行單態(tài)化:
    • 編譯器會為我們用來替換泛型參數的每一個具體類型生成對應函數和方法的非泛型實現。
  • 通過單態(tài)化生成的代碼會執(zhí)行靜態(tài)派發(fā)(static dispatch),在編譯過程中確定調用的具體方法
  • 動態(tài)派發(fā)(dynamic dispatch):
    • 無法在編譯過程中確定你調用的究竟是哪一種方法
    • 編譯器會產生額外的代碼以便在運行時找出希望調用的方法
  • 使用 trait 對象,會執(zhí)行動態(tài)派發(fā):
    • 產生運行時開銷
    • 阻止編譯器內聯方法代碼,使得部分優(yōu)化操作無法進行

Trait 對象必須保證對象安全

  • 只能把滿足對象安全(object-safe)的 trait 轉化為 trait 對象
  • Rust采用一系列規(guī)則來判定某個對象是否安全,只需記住兩條:
    • 方法的返回類型不是 Self
    • 方法中不包含任何泛型類型參數

lib.rs 文件

pub trait Draw {
  fn draw(&self);
}

pub trait Clone {
  fn clone(&self) -> Self;
}

pub struct Screen {
  pub components: Vec<Box<dyn Clone>>, // 報錯
}

三、實現面向對象的設計模式

狀態(tài)模式

  • 狀態(tài)模式(state pattern)是一種面向對象設計模式:
    • 一個值擁有的內部狀態(tài)由數個狀態(tài)對象(state object)表達而成,而值的行為則隨著內部狀態(tài)的改變而改變
  • 使用狀態(tài)模式意味著:
    • 業(yè)務需求變化時,不需要修改持有狀態(tài)的值的代碼,或者使用這個值的代碼
    • 只需要更新狀態(tài)對象內部的代碼,以便改變其規(guī)則,或者增加一些新的狀態(tài)對象

例子:發(fā)布博客的工作流程 main.rs

use blog::Post;

fn main() {
  let mut post = Post::new();
  
  post.add_text("I ate a salad for lunch today");
  assert_eq!("", post.content());
  
  post.request_review();
  assert_eq!("", post.content());
  
  post.approve();
  assert_eq!("I ate a salad for lunch today", post.content());
}

lib.rs 文件

pub struct Post {
  state: Option<Box<dyn State>>,
  content: String,
}

impl Post {
  pub fn new() -> Post {
    Post {
      state: Some(Box::new(Draft {})),
      content: String::new(),
    }
  }
  pub fn add_text(&mut self, text: &str) {
    self.content.push_str(text);
  }
  
  pub fn content(&self) -> &str {
    ""
  }
  
  pub fn request_review(&mut self) {
    if let Some(s) = self.state.take() {
      self.state = Some(s.request_review())
    }
  }
  
  pub fn approve(&mut self) {
    if let Some(s) = self.state.take() {
      self.state = Some(s.approve())
    }
  }
}

trait State {
  fn request_review(self: Box<Self>) -> Box<dyn State>;
  fn approve(self: Box<Self>) -> Box<dyn State>;
}

struct Draft {}

impl State for Draft {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    Box::new(PendingReview {})
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    self
  }
}

struct PendingReview {}

impl State for PendingRevew {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    self
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    Box::new(Published {})
  }
}

struct Published {}

impl State for Published {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    self
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    self
  }
}

修改之后:

pub struct Post {
  state: Option<Box<dyn State>>,
  content: String,
}

impl Post {
  pub fn new() -> Post {
    Post {
      state: Some(Box::new(Draft {})),
      content: String::new(),
    }
  }
  pub fn add_text(&mut self, text: &str) {
    self.content.push_str(text);
  }
  
  pub fn content(&self) -> &str {
    self.state.as_ref().unwrap().content(&self)
  }
  
  pub fn request_review(&mut self) {
    if let Some(s) = self.state.take() {
      self.state = Some(s.request_review())
    }
  }
  
  pub fn approve(&mut self) {
    if let Some(s) = self.state.take() {
      self.state = Some(s.approve())
    }
  }
}

trait State {
  fn request_review(self: Box<Self>) -> Box<dyn State>;
  fn approve(self: Box<Self>) -> Box<dyn State>;
  fn content<'a>(&self, post: &'a Post) -> &'a str {
    ""
  }
}

struct Draft {}

impl State for Draft {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    Box::new(PendingReview {})
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    self
  }
}

struct PendingReview {}

impl State for PendingRevew {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    self
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    Box::new(Published {})
  }
}

struct Published {}

impl State for Published {
  fn request_review(self: Box<Self>) -> Box<dyn State> {
    self
  }
  
  fn approve(self: Box<Self>) -> Box<dyn State> {
    self
  }
  
  fn content<'a>(&self, post: &'a Post) -> &'a str {
    &post.content
  }
}

狀態(tài)模式的取舍權衡

  • 缺點:
    • 某些狀態(tài)之間是相互耦合的
    • 需要重復實現一些邏輯代碼

將狀態(tài)和行為編碼為類型

  • 將狀態(tài)編碼為不同的類型:
    • Rust 類型檢查系統(tǒng)會通過編譯時錯誤來阻止用戶使用無效的狀態(tài)

lib.rs 代碼:

pub struct Post {
  content: String,
}

pub struct DraftPost {
  content: String,
}

impl Post {
  pub fn new() -> DraftPost {
    DraftPost {
      content: String::new(),
    }
  }
  pub fn content(&self) -> &str {
    &self.content
  }
}

impl DraftPost {
  pub fn add_text(&mut self, text: &str) {
    self.content.push_str(text);
  }
  pub fn request_review(self) -> PendingReviewPost {
    PendingReviewPost {
      content: self.content,
    }
  }
}

pub struct PendingReviewPost {
  content: String,
}

impl PendingReviewPost {
  pub fn approve(self) -> Post {
    Post {
      content: self.content,
    }
  }
}

main.rs 代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-419898.html

use blog::Post;

fn main() {
  let mut post = Post::new();
  
  post.add_text("I ate a salad for lunch today");
  
  let post = post.request_review();
  
  let post = post.approve();
  
  assert_eq!("I ate a salad for lunch today", post.content());
}

總結

  • Rust 不僅能夠實現面向對象的設計模式,還可以支持更多的模式
  • 例如:將狀態(tài)和行為編碼為類型
  • 面向對象的經典模式并不總是 Rust 編程實踐中的最佳選擇,因為 Rust具有所有權等其它面向對象語言沒有的特性!

到了這里,關于Rust編程語言入門之Rust的面向對象編程特性的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Go語言面向對象編程

    注:安裝教程 上一篇 1.1、簡單實例 1.2、指針 1、Go語言中的面向對象最為直觀,也無需支付額外的成本。如果要求對象必須以指針傳遞,這有時會是個額外成本,因為對象有時很?。ū热?字節(jié)),用指針傳遞并不劃算。 只有在你需要修改對象的時候,才必須用指針。它不是

    2024年02月06日
    瀏覽(28)
  • 【轉載】R語言 面向對象編程

    轉載自:R語言教程 面向對象的編程側重于數據和對象,而不是程序。面向對象的模型有助于我們對現實生活中的對象進行建模。為了在數據科學領域出類拔萃,掌握面向對象的編程概念很重要。每個程序都有特殊類型的類。在本教程中,將重點討論R語言中的S3和S4類、泛型函

    2024年01月20日
    瀏覽(22)
  • 【JAVA】面向對象的編程語言(繼承篇)

    【JAVA】面向對象的編程語言(繼承篇)

    個人主頁:【??個人主頁】 系列專欄:【??初識JAVA】 在之前的文章中,我們介紹過面向對象的編程語言,今天我們就來就進入到JAVA面對對象的編程世界,今天我們主要來介紹面向對象的編程范式中一個重要的概念——繼承。 繼承是java面向對象編程技術的一塊基石,因為

    2024年02月09日
    瀏覽(23)
  • 【跟小嘉學 Rust 編程】十三、函數式語言特性:迭代器和閉包

    【跟小嘉學 Rust 編程】一、Rust 編程基礎 【跟小嘉學 Rust 編程】二、Rust 包管理工具使用 【跟小嘉學 Rust 編程】三、Rust 的基本程序概念 【跟小嘉學 Rust 編程】四、理解 Rust 的所有權概念 【跟小嘉學 Rust 編程】五、使用結構體關聯結構化數據 【跟小嘉學 Rust 編程】六、枚舉

    2024年02月11日
    瀏覽(27)
  • 【Go 基礎篇】走進Go語言的面向對象編程世界

    【Go 基礎篇】走進Go語言的面向對象編程世界

    歡迎各位編程愛好者們!今天我們將進入Go語言的面向對象編程(OOP)世界,一窺這門語言如何運用OOP思想來組織和構建程序。無論你是初學者還是有一些經驗的開發(fā)者,本文都將為你揭示Go語言中的OOP特性、方法和最佳實踐。 面向對象編程是一種程序設計范式,它以對象為

    2024年02月10日
    瀏覽(22)
  • Rust編程語言入門之模式匹配

    模式是Rust中的一種特殊語法,用于匹配復雜和簡單類型的結構 將模式與匹配表達式和其他構造結合使用,可以更好地控制程序的控制流 模式由以下元素(的一些組合)組成: 字面值 解構的數組、enum、struct 和 tuple 變量 通配符 占位符 想要使用模式,需要將其與某個值進行

    2023年04月22日
    瀏覽(24)
  • Rust編程語言入門之無畏并發(fā)

    Concurrent:程序的不同部分之間獨立的執(zhí)行(并發(fā)) Parallel:程序的不同部分同時運行(并行) Rust無畏并發(fā):允許你編寫沒有細微Bug的代碼,并在不引入新Bug的情況下易于重構 注意:本文中的”并發(fā)“泛指 concurrent 和 parallel 在大部分OS里,代碼運行在進程(process)中,OS同時

    2023年04月19日
    瀏覽(26)
  • Rust編程語言入門之智能指針

    指針:一個變量在內存中包含的是一個地址(指向其它數據) Rust 中最常見的指針就是”引用“ 引用: 使用 借用它指向的值 沒有其余開銷 最常見的指針類型 智能指針是這樣一些數據結構: 行為和指針相似 有額外的元數據和功能 通過記錄所有者的數量,使一份數據被多個

    2023年04月16日
    瀏覽(26)
  • 【學習筆記】C#基礎 - 由C/C++衍生出來的面向對象的編程語言

    【學習筆記】C#基礎 - 由C/C++衍生出來的面向對象的編程語言

    1、基本語法 2、類的命名 必須以 A-Z / _ / @ 開頭,不能是數字,之后可以跟 A-Z 、 0-9 、 _ 、 @ 不能包含任何空格或特殊符號,比如 ?-+!#%^*()[]{}.;:\\\"\\\'/ 不能與同名(除非添加 @ 前綴,@不作為標識符本身的一部分),不能與類庫同名 必須區(qū)分大小寫(PascalCase命名法) 3、關

    2024年02月07日
    瀏覽(23)
  • Rust編程語言入門之cargo、crates.io

    通過 release profile 來自定義構建 在https://crates.io/上發(fā)布庫 通過 workspaces 組織大工程 從 https://crates.io/來安裝庫 使用自定義命令擴展 cargo release profile: 是預定義的 可自定義:可使用不同的配置,對代碼編譯擁有更多的控制 每個 profile 的配置都獨立于其它的 profile cargo 主要的

    2023年04月09日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包