odbc insert中包含中文_在哈希图中存储具有关联值的键

我们的最后一个常见集合是哈希图。类型HashMap 存储类型键到类型K值的映射V。它通过散列函数执行此操作 ,该函数确定如何将这些键和值放入内存中。许多编程语言都支持这种数据结构,但是它们经常使用不同的名称,例如哈希,地图,对象,哈希表,字典或关联数组,仅举几例。

011d5c7d57cccecccafd13ff5954d435.png

当您不希望像使用向量那样使用索引来查找数据时,而是通过使用可以是任何类型的键来查找数据时,哈希映射很有用。例如,在游戏中,您可以在哈希图中跟踪每个团队的得分,在哈希图中每个键是一个团队的名称,值是每个团队的得分。给定一个团队名称,您可以检索其得分。

在本节中,我们将介绍哈希映射的基本API,但是更多的东西隐藏在HashMap标准库定义的函数中。与往常一样,请查阅标准库文档以获取更多信息。

创建一个新的哈希图

您可以使用创建空哈希图,new并使用添加元素insert。在清单8-20中,我们跟踪两个名字分别为Blue和Yellow的球队的得分。蓝队以10分开始,黄队以50分开始。

    use std::collections::HashMap;    let mut scores = HashMap::new();    scores.insert(String::from("Blue"), 10);    scores.insert(String::from("Yellow"), 50);

清单8-20:创建一个新的哈希图并插入一些键和值

请注意,我们首先需要use的HashMap标准库中的馆藏部分。在我们的三个常见集合中,该集合是最不常用的集合,因此未包含在序幕中自动纳入范围的功能中。哈希图也没有得到标准库的支持。例如,没有内置的宏来构造它们。

就像向量一样,哈希映射将其数据存储在堆中。它HashMap具有type的键和type的String值i32。像向量一样,哈希映射是同构的:所有键都必须具有相同的类型,并且所有值都必须具有相同的类型。

构造哈希映射的另一种方法是使用迭代器和collect 元组向量上的方法,其中每个元组均由键及其值组成。我们将在第13章的“使用迭代器处理一系列项目”中详细介绍迭代器及其相关方法。该collect方法将数据收集到多种收集类型中,包括HashMap。例如,如果我们在两个单独的向量中具有团队名称和初始得分,则可以使用该zip方法创建一个元组向量,其中“蓝色”与10配对,依此类推。然后,我们可以使用该collect方法将元组的向量转换为哈希图,如清单8-21所示。

    use std::collections::HashMap;    let teams = vec![String::from("Blue"), String::from("Yellow")];    let initial_scores = vec![10, 50];    let mut scores: HashMap<_ _> =        teams.into_iter().zip(initial_scores.into_iter()).collect();

清单8-21:从团队列表和得分列表创建哈希图

HashMap<_ _>这里需要类型注释,因为它可以 collect放入许多不同的数据结构中,除非指定,Rust不知道您想要哪个。但是,对于键和值类型的参数,我们使用下划线,Rust可以根据向量中数据的类型推断哈希映射包含的类型。在清单8-21中,键类型为String,值类型为i32,就像清单8-20中的类型一样。

哈希图和所有权

对于实现Copy特征的类型,如i32,值将复制到哈希图中。对于拥有的值,如String,值将被移动,并且哈希图将成为这些值的所有者,如清单8-22所示。

    use std::collections::HashMap;    let field_name = String::from("Favorite color");    let field_value = String::from("Blue");    let mut map = HashMap::new();    map.insert(field_name, field_value);    // field_name and field_value are invalid at this point, try using them and    // see what compiler error you get!

清单8-22:显示键和值一旦插入就由哈希映射拥有

我们无法使用这些变量,field_name并且field_value在通过调用将该变量移入哈希映射之后insert。

如果我们将对值的引用插入到哈希图中,则这些值将不会移入哈希图中。引用所指向的值必须至少在哈希映射有效期间才有效。我们将在第10章的“使用生命周期验证参考”部分中详细讨论这些问题。

在哈希图中访问值

我们可以通过将哈希值提供给get 方法的键来获取值,如清单8-23所示。

    use std::collections::HashMap;    let mut scores = HashMap::new();    scores.insert(String::from("Blue"), 10);    scores.insert(String::from("Yellow"), 50);    let team_name = String::from("Blue");    let score = scores.get(&team_name);

代码清单8-23:访问哈希图中存储的蓝队得分

在这里,score将具有与Blue团队相关联的价值,结果将是Some(&10)。结果被包装,Some因为get 返回Option;如果哈希图中没有该键的值, get则将返回None。该程序将需要以Option我们在第6章中介绍的一种方式来处理。

我们可以像使用向量一样,通过for循环来遍历哈希图中的每个键/值对:

    use std::collections::HashMap;    let mut scores = HashMap::new();    scores.insert(String::from("Blue"), 10);    scores.insert(String::from("Yellow"), 50);    for (key, value) in &scores {        println!("{}: {}", key, value);    }

此代码将以任意顺序打印每对:

Yellow: 50Blue: 10

更新哈希图

尽管键和值的数量是可以增加的,但每个键一次只能具有一个关联的值。当您想更改哈希图中的数据时,必须决定在键已经分配了值的情况下如何处理这种情况。您可以用新值替换旧值,而完全不考虑旧值。您可以保留旧值,而忽略新值,仅在键尚无值时才添加新值。或者,您可以将旧值和新值结合起来。让我们看看如何做这些!

覆盖价值

如果我们将一个键和一个值插入哈希映射,然后将相同的键插入一个不同的值,则与该键关联的值将被替换。即使清单8-24中的代码调用了insert两次,但哈希映射将只包含一个键/值对,因为我们两次都插入了Blue团队键的值。

    use std::collections::HashMap;    let mut scores = HashMap::new();    scores.insert(String::from("Blue"), 10);    scores.insert(String::from("Blue"), 25);    println!("{:?}", scores);

清单8-24:用特定键替换存储的值

此代码将打印出来{"Blue": 25}。的原始值10已被覆盖。

仅当键没有值时才插入值

通常检查特定键是否具有值,如果没有,请为其插入值。哈希映射为此有一个特殊的API entry ,它将要检查的键作为参数。该entry方法的返回值 是一个称为的枚举Entry,表示可能存在或可能不存在的值。假设我们要检查Yellow团队的密钥是否具有与其关联的值。如果不是,我们要插入值50,蓝色团队也要插入值50。使用entryAPI,代码类似于清单8-25。

    use std::collections::HashMap;    let mut scores = HashMap::new();    scores.insert(String::from("Blue"), 10);    scores.entry(String::from("Yellow")).or_insert(50);    scores.entry(String::from("Blue")).or_insert(50);    println!("{:?}", scores);

清单8-25:使用该entry方法仅在键上无值时插入

的or_insert上方法Entry定义为返回一个可变参考值对于相应的Entry键,如果该键存在,并且如果不是,插入参数作为该键并返回一个可变引用为新的值的新值。这种技术比自己编写逻辑要干净得多,此外,它与借用检查器的配合也更加出色。

运行清单8-25中的代码将显示{"Yellow": 50, "Blue": 10}。第一次呼叫entry将为Yellow小组插入值50的密钥,因为Yellow小组还没有值。第二个调用 entry不会更改哈希映射,因为Blue团队已经具有值10。

根据旧值更新值

哈希映射的另一个常见用例是查找键的值,然后根据旧值对其进行更新。例如,清单8-26显示了用于计算每个单词在某些文本中出现的次数的代码。我们使用带有单词作为键的哈希图,并增加值以跟踪我们看到该单词的次数。如果这是我们第一次看到一个单词,我们将首先插入值0。

    use std::collections::HashMap;    let text = "hello world wonderful world";    let mut map = HashMap::new();    for word in text.split_whitespace() {        let count = map.entry(word).or_insert(0);        *count += 1;    }    println!("{:?}", map);

清单8-26:使用存储单词和计数的哈希图对单词的出现进行计数

此代码将打印出来{"world": 2, "hello": 1, "wonderful": 1}。该 or_insert方法实际上返回&mut V对此键的值的可变引用()。在这里,我们将该可变引用存储在count变量中,因此,为了分配该值,我们必须首先count使用星号(*)取消引用。可变引用在for 循环结束时超出范围,因此所有这些更改都是安全的,并且借用规则允许。

散列函数

默认情况下,HashMap使用“加密强度高”的1哈希功能,该功能可以抵抗拒绝服务(DoS)攻击。这不是可用的最快的哈希算法,但是性能下降带来的更好安全性的权衡是值得的。如果您对代码进行概要分析并发现默认哈希函数对于您的目的而言太慢,则可以通过指定其他hasher来切换到另一个函数 。散列器是实现BuildHasher特征的一种类型。我们将在第10章中讨论特性以及如何实现它们。您不必从头开始实现自己的哈希器; crates.io具有其他Rust用户共享的库,这些库提供实现许多常用哈希算法的哈希器。

1个

https://www.131002.net/siphash/siphash.pdf

概要

当您需要存储,访问和修改数据时,向量,字符串和哈希映射将提供程序中所需的大量功能。这是您现在应该准备解决的一些练习:

  • 给定一个整数列表,请使用向量并返回均值(平均值),中位数(排序时,中间位置的值)和众数(最常出现的值;哈希映射在这里会有所帮助)列表中。
  • 将字符串转换为猪拉丁文。每个单词的第一个辅音移到单词的末尾并添加“ ay”,因此“ first”变成“ irst-fay”。以元音开头的单词在末尾加了“ hay”(“ apple”变成“ apple-hay”)。请记住有关UTF-8编码的详细信息!
  • 使用哈希图和向量,创建一个文本界面,以允许用户将员工姓名添加到公司的部门中。例如,“将Sally添加到工程”或“将Amir添加到销售”。然后,让用户检索部门中所有人员或部门中公司所有人员的列表,并按字母顺序排序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值