最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Rust中實(shí)例化動(dòng)態(tài)對(duì)象的示例詳解

 更新時(shí)間:2025年02月23日 09:39:24   作者:hboot  
這篇文章主要為大家詳細(xì)介紹了Rust中實(shí)例化動(dòng)態(tài)對(duì)象的多種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

在功能開發(fā)中,動(dòng)態(tài)創(chuàng)建或獲取某個(gè)對(duì)象的情況很多。在前端JS開發(fā)中,可以使用工廠函數(shù),通過給定的類型標(biāo)識(shí)創(chuàng)建不同的對(duì)象實(shí)例;還可以通過對(duì)象映射來實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象。

Rust中,我們也可以使用這兩種方式去創(chuàng)建對(duì)象實(shí)例,但實(shí)現(xiàn)書寫的方式可能略有不同;rust還可以通過序列化JSON數(shù)據(jù)時(shí)進(jìn)行枚舉類型匹配。

我們定義好需要測試的數(shù)據(jù)結(jié)構(gòu)體、方法。小狗、小貓有自己的字段、方法,它們有相同的字段name,也有相同的方法say。

use serde_derive::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug)]
struct Dog {
    name: String,
    work: String,
}
impl Dog {
    fn new(name: String, work: String) -> Dog {
        Dog { name, work }
    }
    fn say(&self) {
        println!("{} say wangwang", self.name);
    }
}

#[derive(Deserialize, Serialize, Debug)]
struct Cat {
    name: String,
    age: i32,
}

impl Cat {
    fn new(name: String) -> Cat {
        Cat { name: name, age: 0 }
    }
    fn say(&self) {
        println!("{} say miamiamia", self.name);
    }
}

序列化serde

我們在拿到JSON格式數(shù)據(jù)進(jìn)行序列化時(shí),在rust中是需要確定具體數(shù)據(jù)類型的,但是我們并不知道具體類型,因?yàn)楝F(xiàn)在有兩種類型,要合為一種類型,就需要?dú)w集,使用枚舉enum來定義可能的類型:

#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
enum Animal {
    Dog(Dog),
    Cat(Cat),
}

對(duì)于JSON格式和rust 結(jié)構(gòu)體的互相轉(zhuǎn)換,可以使用serde庫。也正好利用JSON轉(zhuǎn)結(jié)構(gòu)體這一過程,利用轉(zhuǎn)換機(jī)制來實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象。

安裝相關(guān)的庫:

cargo add serde serde_derive serde_json

我們定義一個(gè)JSON格式數(shù)據(jù),使用serde庫進(jìn)行反序列化,并使用match進(jìn)行匹配:

fn main() {
    let data = r#"
    {
        "name":"admin",
        "age":2
    }
    "#;
    let animal = serde_json::from_str(data).unwrap();
    match animal {
        Animal::Dog(dog) => {
            dog.say();
        }
        Animal::Cat(cat) => {
            cat.say();
        }
    };
}

測試運(yùn)行,正常輸出了cat say wangwang。我們修改JSON格式數(shù)據(jù)

let data = r#"
{
    "name":"admin",
    "work":"play"
}
"#;

測試運(yùn)行,正常輸出了dog say wangwang,說明沒有邏輯沒有問題。

待優(yōu)化的地方在于我們使用了match,如果我們需要在多個(gè)地方使用animal,那么這段匹配邏輯就無處不在了。當(dāng)有很多方法時(shí),無法控制具體調(diào)用哪個(gè)方法,就需要不停的去匹配。

我們可以將它們需要調(diào)用公共方法在枚舉類型Animal定義一下,內(nèi)部邏輯根據(jù)不同類型在調(diào)用各自的方法。

impl Animal {
    fn say(&self) {
        match self {
            Animal::Cat(cat) => cat.say(),
            Animal::Dog(dog) => dog.say(),
        }
    }
}

Animal定義公共方法say,然后在序列化JSON數(shù)據(jù)格式時(shí),我們必須要指定數(shù)據(jù)類型:

fn main() {
    let data = r#"
    {
        "name":"admin",
        "age":2,
        "work":"play"
    }
    "#;
    let animal: Animal = serde_json::from_str(data).unwrap();

    animal.say();
}

明確指定了animal: Animal,因?yàn)闆]有其他邏輯幫助rust推斷出具體的類型是什么。也可以這么寫let animal = serde_json::from_str::<Animal>(data).unwrap();

注意

需要注意的是:匹配的不同對(duì)象結(jié)構(gòu)體的字段不能一致,否則會(huì)匹配到枚舉的第一個(gè);如果出現(xiàn)包含的情況,我們需要把被包含的結(jié)構(gòu)體放在前面。

比如小貓也有work字段了:

#[derive(Deserialize, Serialize, Debug)]
struct Cat {
    name: String,
    age: i32,
    work: String,
}

這是我們再去匹配JSON格式數(shù)據(jù),因?yàn)閿?shù)據(jù)里有age,我們希望的是匹配小貓Cat,但是它里面完全包含了小狗的字段Dog,而且枚舉Animal種小狗在前,所以會(huì)直接匹配小狗:

let data = r#"
{
    "name":"admin",
    "age":2,
    "work":"play"
}
"#;

這樣達(dá)不到我們想要的結(jié)果,所以需要注意調(diào)整枚舉值的順序,可以將復(fù)雜數(shù)據(jù)結(jié)構(gòu)放到前面。將Cat放到前面就可以正常工作了。

#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
enum Animal {
    Cat(Cat)
    Dog(Dog),
}

動(dòng)態(tài)類型匹配

上一個(gè)方式是我們拿到了具體對(duì)象的JSON數(shù)據(jù),然后通過序列化,獲取到對(duì)應(yīng)的對(duì)象實(shí)例。如果我們只知道某個(gè)類型,需要根據(jù)類型初始化具體實(shí)例對(duì)象。

我們枚舉實(shí)例對(duì)象的類型,定義字符串轉(zhuǎn)枚舉類型的方法:

#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
enum AnimalType {
    Dog,
    Cat
}
impl AnimalType {
    fn str_to_animal_type(str: &str) -> AnimalType {
        match str {
            "dog" => AnimalType::Dog,
            "cat" => AnimalType::Cat,
            _ => panic!("unknown type"),
        }
    }
}

調(diào)用AnimalType獲取到枚舉類型,然后通過匹配類型來實(shí)例化對(duì)象,這跟上面的序列化JSON格式后續(xù)處理方式一致。

fn main() {
    let names = "dog";

    match AnimalType::str_to_animal_type(names) {
        AnimalType::Dog => {
            let dog = Dog {
                name: "admin".to_string(),
                work: "play".to_string(),
            };
            dog.say();
        }
        AnimalType::Cat => {
            let cat = Cat {
                name: "admin".to_string(),
                age: 2,
                work: "play".to_string(),
            };

            cat.say();
        }
    }
}

Trait 特質(zhì)

trait是rust中特有的類型,它可以定義對(duì)象的行為,然后可以被其他對(duì)象實(shí)現(xiàn)。實(shí)現(xiàn)它的對(duì)象可以擁有相同的行為,但是可以擁有不同的內(nèi)部邏輯。

這可以保證我們在動(dòng)態(tài)獲取到不同的對(duì)象實(shí)例,調(diào)用它們的方法時(shí)保證方法存在。在創(chuàng)建動(dòng)態(tài)對(duì)象時(shí),因?yàn)椴恢艟唧w大小,需要使用Box<dyn Trait>定義動(dòng)態(tài)對(duì)象。

trait AnimalTrait {
    fn say(&self);
}

然后在各個(gè)類型中實(shí)現(xiàn)AnimalTrait,并實(shí)現(xiàn)公共方法say。

impl AnimalTrait for Dog {
    fn say(&self) {
        println!("{} say wangwang", self.name);
    }
}
impl AnimalTrait for Cat {
    fn say(&self) {
        println!("{} say miamiamia", self.name);
    }
}

定義類型都實(shí)現(xiàn)AnimalTrait的方法,就可以放心的使用Box<dyn AnimalTrait>提供的動(dòng)態(tài)對(duì)象了。

impl AnimalType {
    fn str_to_animal(str: &str) -> Box<dyn AnimalTrait> {
        match str {
            "dog" => Box::new(Dog::new("admin".to_string(), "play".to_string())),
            "cat" => Box::new(Cat::new("test".to_string())),
            _ => panic!("unknown type"),
        }
    }
}

方法str_to_animal通過類型匹配獲取到對(duì)應(yīng)的實(shí)例對(duì)象,現(xiàn)在我們不需要再匹配里直接調(diào)用方法了。我們拿到動(dòng)態(tài)對(duì)象,想調(diào)用那個(gè)方法就用哪個(gè)。

fn main() {
    let names = "dog";
    let animal = AnimalType::str_to_animal(names);
    animal.say();
}

這樣就很方便的進(jìn)行動(dòng)態(tài)對(duì)象的傳遞,我們不需要關(guān)心該調(diào)用哪個(gè)方法,是否需要導(dǎo)入指定的方法。rust通過Box<dyn AnimalTrait>會(huì)自動(dòng)調(diào)用合適的實(shí)現(xiàn)。

From/Into 類型強(qiáng)轉(zhuǎn)

我們定義了AnimalTrait規(guī)范了動(dòng)態(tài)對(duì)象的行為,它們在實(shí)現(xiàn)了AnimalTrait后,就可以根據(jù)動(dòng)態(tài)對(duì)象調(diào)用它的公共方法了。

但在根據(jù)類型創(chuàng)建動(dòng)態(tài)對(duì)象時(shí),仍然定義了枚舉AnimalType的方法str_to_animal并調(diào)用從而匹配到對(duì)應(yīng)的動(dòng)態(tài)對(duì)象。

我們還可以使用Fromtrait,通過讓AnimalTrait實(shí)現(xiàn)Fromtrait,從而直接使用into方法讓字符串類型轉(zhuǎn)為動(dòng)態(tài)對(duì)象。

impl From<&str> for Box<dyn AnimalTrait> {
    fn from(value: &str) -> Self {
        match value {
            "dog" => Box::new(Dog::new("admin".to_string(), "play".to_string())),
            "cat" => Box::new(Cat::new("test".to_string())),
            _ => panic!("unknown type"),
        }
    }
}

這樣的實(shí)現(xiàn)可以減少在創(chuàng)建動(dòng)態(tài)對(duì)象時(shí)的顯示函數(shù)調(diào)用,我們在使用的時(shí)候直接調(diào)用into()方法即可:

fn main{
    let dog: Box<dyn AnimalTrait> = "dog".into();
    dog.say();
}

HashMap映射類型

以上實(shí)現(xiàn)方案難免都使用了match進(jìn)行匹配,而我們在之前說的映射對(duì)象的實(shí)現(xiàn),則可以避免match的匹配。

通過HashMap初始化類型映射結(jié)構(gòu)體對(duì)象,在使用時(shí)通過自定義方法get傳入指定的類型,得到動(dòng)態(tài)類型。

struct AnimalFactory {
    map: HashMap<String, Box<dyn Fn() -> Box<dyn AnimalTrait>>>,
}

我們定義了一個(gè)結(jié)構(gòu)體AnimalFactory,其中包含一個(gè)HashMap類型的字段map,用于存儲(chǔ)類型與創(chuàng)建函數(shù)的映射關(guān)系。

注意到HashMap的值是一個(gè)閉包函數(shù)而不是直接動(dòng)態(tài)類型,如果直接定義HashMap<String, Box<dyn AnimalTrait>>,我們在初始化時(shí)就必須實(shí)例化創(chuàng)建對(duì)象實(shí)例,這就導(dǎo)致具體對(duì)象的實(shí)例只有一個(gè)而避免不了處理所有權(quán)的問題。如果我們需要傳遞所有權(quán),就必須使用Arc了。

定義了工廠結(jié)構(gòu)體AnimalFactory,定義初始化函數(shù)new:

impl AnimalFactory {
    fn new() -> Self {
        map.insert(
            "dog".to_string(),
            Box::new(|| {
                Box::new(Dog::new("admin".to_string(), "play".to_string())) as Box<dyn AnimalTrait>
            }) as Box<dyn Fn() -> Box<dyn AnimalTrait>>,
        );
        map.insert(
            "cat".to_string(),
            Box::new(|| Box::new(Cat::new("test".to_string()))),
        );

        AnimalFactory { map }
    }
}

由于HashMap需要定義具體的類型,我們在插入類型Dog時(shí)無法匹配定義的Box<dyn Fn() -> Box<dyn AnimalTrait>>導(dǎo)致報(bào)錯(cuò),這就需要我們手動(dòng)強(qiáng)轉(zhuǎn)類型。

為了簡化類型書寫,我們定義一個(gè)類型替代:

type AnimalDynType = Box<dyn Fn() -> Box<dyn AnimalTrait>>;

我們已經(jīng)初始化了映射表,定義根據(jù)具體類型獲取動(dòng)態(tài)對(duì)象的方法:

impl AnimalFactory {
    fn get(&self, name: &str) -> Box<dyn AnimalTrait> {
        match self.map.get(name) {
            Some(create_fn) => create_fn(),
            None => panic!("not found"),
        }
    }
}

在使用時(shí),首先創(chuàng)建一個(gè)AnimalFactory對(duì)象,然后調(diào)用get方法,傳入具體的類型名稱,即可獲取對(duì)應(yīng)的動(dòng)態(tài)對(duì)象。

fn main() {
    let animal = AnimalFactory::new();

    let dog = animal.get_animal("dog");
    dog.say();
}

最后

這幾種實(shí)現(xiàn)方式都有一定的使用場景,根據(jù)實(shí)際需求選擇合適的方式。

到此這篇關(guān)于Rust中實(shí)例化動(dòng)態(tài)對(duì)象的示例詳解的文章就介紹到這了,更多相關(guān)Rust實(shí)例化動(dòng)態(tài)對(duì)象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MacBook Pro安裝rust編程環(huán)境的過程

    MacBook Pro安裝rust編程環(huán)境的過程

    rustup是一個(gè)用于管理Rust版本和工具鏈的工具,這篇文章主要介紹了MacBook Pro安裝rust編程環(huán)境的過程,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • Rust?編程語言中的所有權(quán)ownership詳解

    Rust?編程語言中的所有權(quán)ownership詳解

    這篇文章主要介紹了Rust?編程語言中的所有權(quán)ownership詳解的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié)

    Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié)

    這篇文章主要為大家介紹了Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Rust生命周期常見誤區(qū)(中英對(duì)照)全面指南

    Rust生命周期常見誤區(qū)(中英對(duì)照)全面指南

    這篇文章主要WEIDJAI?介紹了Rust生命周期常見誤區(qū)(中英對(duì)照)的全面指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Rust中Protobuf使用詳解

    Rust中Protobuf使用詳解

    本文介紹了如何在Rust中使用Protobuf進(jìn)行序列化和反序列化,并介紹了如何在項(xiàng)目中使用生成的Rust代碼,通過include!宏和mod.rs文件的配置,可以方便地在Rust項(xiàng)目中使用Protobuf,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Rust常用特型之Drop特型

    Rust常用特型之Drop特型

    本文主要介紹了Rust常用特型之Drop特型,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-03-03
  • 如何在Rust中處理命令行參數(shù)和環(huán)境變量

    如何在Rust中處理命令行參數(shù)和環(huán)境變量

    在本章節(jié)中, 我們探討了Rust處理命令行參數(shù)的常見的兩種方式和處理環(huán)境變量的兩種常見方式,感興趣的朋友一起看看吧
    2023-12-12
  • Rust時(shí)間庫Chrono最佳使用實(shí)踐

    Rust時(shí)間庫Chrono最佳使用實(shí)踐

    本文介紹了Rust中常用的日期時(shí)間處理庫chrono,對(duì)比了標(biāo)準(zhǔn)庫std::time和chrono的功能和適用場景,并詳細(xì)講解了chrono的核心數(shù)據(jù)類型、主要操作、進(jìn)階功能以及最佳實(shí)踐,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Rust 函數(shù)式編程的具體使用

    Rust 函數(shù)式編程的具體使用

    本文主要介紹了Rust 函數(shù)式編程的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-06-06
  • Rust之智能指針的用法

    Rust之智能指針的用法

    在Rust中,智能指針是管理內(nèi)存所有權(quán)和生命周期的核心工具,本文主要介紹了Rust之智能指針的用法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03

最新評(píng)論

丁青县| 应用必备| 鄂伦春自治旗| 淳安县| 西藏| 湖口县| 邓州市| 巩义市| 天长市| 娱乐| 西林县| 枝江市| 阿拉善盟| 林周县| 长乐市| 临朐县| 中宁县| 莲花县| 灵丘县| 和政县| 鄂伦春自治旗| 沅江市| 加查县| 新野县| 十堰市| 珠海市| 本溪市| 阿克苏市| 张家界市| 承德县| 南丰县| 吉木萨尔县| 澄迈县| 江川县| 普陀区| 故城县| 南澳县| 梁山县| 视频| 建宁县| 如皋市|