30天拿下Rust之HashMap

这篇具有很好参考价值的文章主要介绍了30天拿下Rust之HashMap。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

        HashMap,被称为哈希表或散列表,是一种可以存储键值对的数据结构。它使用哈希函数将键映射到存储位置,以便可以快速检索和更新元素。这种数据结构在许多编程语言中都存在,而在Rust中,它被实现为HashMap<K, V>。其中,K表示键的类型,V表示值的类型。HashMap以哈希表为基础实现,允许我们在常数平均时间复杂度内完成插入、删除和查找操作。

HashMap的创建

        Rust标准库中提供了std::collections::HashMap<K, V>,这是一个关联数组或映射。其中,K是键类型,必须实现Eq和Hash traits以确保键的唯一性和能够进行哈希计算。V是值类型,可以是任何Rust支持的类型。

        每个键都会通过哈希函数转化为一个索引,并以此存储对应的值,从而使得通过键快速定位到值成为可能。当两个不同的键通过哈希函数得到相同的索引时,会发生“哈希冲突”。此时,HashMap会通过开放寻址法或者链地址法等策略来解决这个问题。

        要使用HashMap,必须先引入std::collections::HashMap模块。新建HashMap,主要有以下几种方式。

        1、使用new函数创建一个新的、空的HashMap。

use std::collections::HashMap;

fn main() {
    // 创建一个空的HashMap,键类型为String,值类型为i32
    let mut map_fruit: HashMap<String, i32> = HashMap::new();
    
    // 插入一些键值对
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);
    // 输出:{"Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

        2、新建带有元素的HashMap。通过传入一个键值对的集合(比如:数组、切片或迭代器),我们可以在创建HashMap的同时初始化它。这可以通过collect方法来实现,它通常与vec!宏或数组字面量一起使用,以创建包含(key, value)元组的集合。在下面的示例代码中,我们首先创建了一个HashMap。它的键是String类型,值是i32类型。然后,我们使用vec!宏创建了一个包含三个(key, value)元组的向量,并使用into_iter方法将其转换为迭代器。最后,我们使用collect方法将其收集到一个HashMap中。

use std::collections::HashMap;

fn main() {
    let map_fruit: HashMap<String, i32> = vec![
        ("Lemon".to_string(), 66), 
        ("Apple".to_string(), 99)].into_iter().collect();
    
    // 输出:{"Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

        3、HashMap::from是一个创建HashMap的便捷方法,主要用于从实现了IntoIterator特征且迭代器产出元组 (K, V) 的类型创建一个HashMap。

use std::collections::HashMap;

fn main() {
    let pairs = [("Lemon".to_string(), 66), ("Apple".to_string(), 99)];
    let map_fruit = HashMap::from(pairs);

    // 输出:{"Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

        4、使用with_capacity函数创建预先分配指定容量的HashMap。注意:预设容量只是预留空间,实际使用的数量会根据插入的键值对自动增长。

use std::collections::HashMap;

fn main() {
    // 创建一个初始容量为5的HashMap
    let mut map_fruit: HashMap<String, i32> = HashMap::with_capacity(5);
    
    // 插入一些键值对
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);
    // 输出:{"Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

HashMap的访问

        HashMap是一个存储键值对的数据结构,并且可以通过键来快速检索值。为了访问HashMap中的值,我们可以使用get方法或get_mut方法,具体取决于是否需要获取值的可变引用。

        1、get方法用于获取与给定键相关联的值的不可变引用。如果键存在于HashMap中,get将返回Some(value),其中value是与该键相关联的值的引用。如果键不存在,它将返回None。

use std::collections::HashMap;

fn main() {
    let mut map_fruit = HashMap::new();
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);

    // 访问存在的键
    if let Some(value) = map_fruit.get("Apple") {
        println!("found value: {}", value);
    } else {
        println!("not found");
    }
  
    // 访问不存在的键
    if let Some(value) = map_fruit.get("Peach") {
        println!("found value: {}", value);
    } else {
        println!("not found");
    }
}

        2、如果我们需要获取值的可变引用以便修改它,则应该使用get_mut方法。与get方法类似,如果键存在于HashMap中,get_mut将返回Some(&mut value),其中&mut value是与该键相关联的值的可变引用。如果键不存在,它将返回None。

use std::collections::HashMap;

fn main() {
    let mut map_fruit = HashMap::new();
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);

    // 访问存在的键
    if let Some(value) = map_fruit.get_mut("Apple") {
        *value = 100;
    } else {
        println!("not found");
    }

    // 输出:{"Apple": 100, "Lemon": 66}
    println!("{:?}", map_fruit);
  
    // 访问不存在的键
    if let Some(value) = map_fruit.get_mut("Peach") {
        println!("found value: {}", value);
    } else {
        println!("not found");
    }
}

HashMap的修改

        1、插入新键值对。如果键不存在,使用insert方法将添加一个新的键值对。如果键已经存在,则会替换原有的值。

use std::collections::HashMap;

fn main() {
    // 创建一个空的HashMap,键类型为String,值类型为i32
    let mut map_fruit: HashMap<String, i32> = HashMap::new();
    
    // 插入一些键值对
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);
    // 输出:{"Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

        2、如果需要根据键是否存在来执行不同的操作(比如:只在键不存在时插入值,或者在键存在时更新值),可以使用entry API。这提供了更细粒度的控制,并避免了不必要的查找。entry方法会根据键是否存在返回一个Entry枚举;or_insert方法会在键不存在时插入给定的值,并返回键的值的可变引用;and_modify方法会修改现有的值。

use std::collections::HashMap;

fn main() {
    let mut map_fruit = HashMap::new();
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);

    // 使用entry API插入新的键值对,并修改值为原来的2倍
    map_fruit.entry("Peach".to_string()).or_insert(256);
    map_fruit.entry("Peach".to_string()).and_modify(|v| *v *= 2);
    // 输出: {"Peach": 512, "Lemon": 66, "Apple": 99}
    println!("{:?}", map_fruit);
}

        3、使用remove方法可以移除指定键的键值对。当我们调用remove方法并传入一个键时,如果该键存在于HashMap中,它会返回与该键相关联的值,并从HashMap中删除该键值对。如果键不存在,会返回None。

use std::collections::HashMap;

fn main() {
    let mut map_fruit = HashMap::new();
    map_fruit.insert("Lemon".to_string(), 66);
    map_fruit.insert("Apple".to_string(), 99);

    // 尝试删除并获取"Lemon"的值,会成功
    if let Some(value) = map_fruit.remove("Lemon") {
        println!("{} removed", value);
    } else {
        println!("not found");
    }

    // 尝试删除并获取"Peach"的值,会失败
    if let Some(value) = map_fruit.remove("Peach") {
        println!("{} removed", value);
    } else {
        println!("not found");
    }

    // 输出: {"Apple": 99}
    println!("{:?}", map_fruit);
}

HashMap的遍历

        在Rust中,我们可以使用多种方式来遍历HashMap,包括:遍历所有的键、遍历所有的值、同时遍历键和值。

        1、遍历所有的键。我们可以使用keys()方法来获取一个包含所有键的迭代器,并遍历它们。

use std::collections::HashMap;

fn main() {
    let pairs = [("Lemon".to_string(), 66), ("Apple".to_string(), 99)];
    let map_fruit = HashMap::from(pairs);

    // 分别输出:Lemon Apple
    for key in map_fruit.keys() {
        println!("{}", key);
    }
}

        2、遍历所有的值。我们可以使用values()方法来获取一个包含所有值的迭代器,并遍历它们。

use std::collections::HashMap;

fn main() {
    let pairs = [("Lemon".to_string(), 66), ("Apple".to_string(), 99)];
    let map_fruit = HashMap::from(pairs);

    // 分别输出:99 66
    for value in map_fruit.values() {
        println!("{}", value);
    }
}

        3、同时遍历键和值。如果需要同时访问键和值,我们可以使用iter()方法,它会返回一个包含键值对引用的迭代器。

use std::collections::HashMap;

fn main() {
    let pairs = [("Lemon".to_string(), 66), ("Apple".to_string(), 99)];
    let map_fruit = HashMap::from(pairs);

    // 分别输出:Apple: 99 Lemon: 66
    for (key, value) in map_fruit.iter() {
        println!("{}: {}", key, value);
    }
}

        4、遍历并修改值。如果需要遍历HashMap并修改其中的值,我们可以使用iter_mut()方法,它会返回一个包含可变键值对引用的迭代器。注意:当使用iter_mut()方法时,不能有其他对HashMap或其任何元素的可变引用。因为Rust的借用规则要求:在同一时间,变量只能有一个可变引用存在。

use std::collections::HashMap;

fn main() {
    let pairs = [("Lemon".to_string(), 66), ("Apple".to_string(), 99)];
    let mut map_fruit = HashMap::from(pairs);

    // 修改值为原来的10倍
    for (key, value) in map_fruit.iter_mut() {
        *value *= 10; 
    }

    // 分别输出:Lemon: 660 Apple: 990
    for (key, value) in map_fruit.iter() {
        println!("{}: {}", key, value);
    }
}

HashMap的所有权

        在Rust中,HashMap对插入其中的键值对的所有权规则,遵循Rust语言的核心所有权原则。这意味着,当我们将一个值放入HashMap时,会根据值的类型决定所有权如何转移。

        1、复制所有权。对于实现了Copy特征的类型(比如:整数、浮点数等基本类型),插入HashMap时不会发生所有权转移,而是进行值的复制。

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    let number: i32 = 66;
    map.insert("Lemon", number);
    
    // 这里仍可以继续使用number,因为复制了一份
    println!("{}", number);
}

        2、转移所有权。如果插入到HashMap中的值是不可复制的类型(比如:String或自定义结构体),那么当调用insert方法时,该值的所有权会被转移给HashMap。这意味着,原变量将不再有效,并且不能再被使用。

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    let peach = String::from("Peach");
    // peach的所有权转移到了HashMap中
    map.insert("Fruit", peach);
    
    // 这里访问peach会导致编译错误,因为它已经不再拥有所有权
    // println!("{}", peach);
}

        3、引用所有权。如果想要存储指向数据的引用,而不是数据本身,可以使用引用类型(比如:&str或&T)。但是,引用的生命周期必须与引用的对象保持一致,确保在整个引用存在期间,对象也依然有效。文章来源地址https://www.toymoban.com/news/detail-840971.html

use std::collections::HashMap;

fn main() {
    let text = String::from("CSDN");
    let mut map = HashMap::new();
    map.insert("Hello", &text);
    // text必须一直有效,因为HashMap持有对它的引用
}

到了这里,关于30天拿下Rust之HashMap的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 30天拿下Rust之生命周期

    概述         在Rust中,生命周期是一个非常重要的概念,是保证内存安全和防止悬垂引用的核心机制之一。通过精确地跟踪引用的生命周期,Rust能够在编译阶段就防止许多其他语言在运行时才会遇到的内存问题。在Rust中,生命周期代表了引用的有效时间段。当我们创建

    2024年03月20日
    浏览(45)
  • 30天拿下Rust之面向对象

    概述         在编程语言的世界中,Rust以其独特的内存安全、并发控制和高性能特性吸引了众多开发者。虽然Rust并非传统的面向对象编程语言(比如:C++、Java),但它依然支持并提供了一种颇具特色的面向对象编程方式,以实现类似于面向对象的编程范式。        

    2024年04月15日
    浏览(40)
  • 30天拿下Rust之错误处理

    概述         在软件开发领域,对错误的妥善处理是保证程序稳定性和健壮性的重要环节。Rust作为一种系统级编程语言,以其对内存安全和所有权的独特设计而著称,其错误处理机制同样体现了Rust的严谨与实用。在Rust中,错误处理通常分为两大类:不可恢复的错误和可

    2024年03月21日
    浏览(66)
  • 30天拿下Rust之高级类型

    概述         Rust作为一门系统编程语言,以其独特的内存管理方式和强大的类型系统著称。其中,高级类型的应用,为Rust的开发者提供了丰富的编程工具和手段,使得开发者可以更加灵活和高效地进行编程。 Newtype模式         Newtype模式是一种轻量级的设计模式,用

    2024年04月15日
    浏览(43)
  • 30天拿下Rust之Trait

    概述         在Rust中,Trait是一个核心概念,它允许我们定义类型应该具有的行为。Trait类似于其他语言中的接口,但Rust的Trait更为强大和灵活。它不仅定义了一组方法,还允许我们指定方法的默认实现、泛型约束和继承。通过Trait,我们可以定义一组方法的签名和关联类

    2024年03月17日
    浏览(35)
  • 30天拿下Rust之图形编程

    概述         Rust语言以其卓越的安全性、性能和可靠性赢得了广大开发者的青睐,逐渐在系统编程、网络服务、游戏开发等领域崭露头角。随着Rust生态的日益繁荣,图形编程领域也涌现出一批优秀的框架和库,使得用Rust进行高效、安全的图形应用开发成为可能。 图形库

    2024年04月17日
    浏览(37)
  • 30天拿下Rust之输入输出

    概述         在软件开发中,输入输出(I/O)是任何应用程序的基本构建模块。Rust作为一门注重安全和性能的语言,在其标准库中提供了强大的I/O功能。这些功能使得Rust程序员能够非常轻松地进行标准I/O、文件读写等操作。 标准I/O         在Rust中,标准输入通常通

    2024年03月24日
    浏览(39)
  • 30天拿下Rust之字符串

    概述         在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:str和String。其中,str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实

    2024年03月12日
    浏览(45)
  • 30天拿下Rust之所有权

    概述         在编程语言的世界中,Rust凭借其独特的所有权机制脱颖而出,为开发者提供了一种新颖而强大的工具来防止内存错误。这一特性不仅确保了代码的安全性,还极大地提升了程序的性能。在Rust中,所有权是一种编译时检查机制,用于追踪哪些内存或资源何时可

    2024年03月08日
    浏览(37)
  • 30天拿下Rust之unsafe代码

    概述         在Rust语言的设计哲学中,\\\"安全优先\\\" 是其核心原则之一。然而,在追求极致性能或者与底层硬件进行交互等特定场景下,Rust提供了unsafe。unsafe代码允许开发者暂时脱离Rust的安全限制,直接操作内存和执行低级操作。虽然unsafe代码在某些情况下是必要

    2024年04月17日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包