【Rust】Rust学习 第八章常见集合

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

Rust 标准库中包含一系列被称为 集合collections)的非常有用的数据结构。大部分其他数据类型都代表一个特定的值,不过集合可以包含多个值。不同于内建的数组和元组类型,这些集合指向的数据是储存在堆上的,这意味着数据的数量不必在编译时就已知,并且还可以随着程序的运行增长或缩小。每种集合都有着不同功能和成本,而根据当前情况选择合适的集合,这是一项始终成长的技能。

三个在 Rust 程序中被广泛使用的集合:

  • vector 允许一个挨着一个地储存一系列数量可变的值
  • 字符串string)是一个字符的集合。之前见过 String 类型,不过在本章将深入了解。
  • 哈希 maphash map)允许我们将值与一个特定的键(key)相关联。这是一个叫做 map 的更通用的数据结构的特定实现。

8.1 vector

第一个类型是 Vec<T>,也被称为 vector。vector 允许我们在一个单独的数据结构中储存多于一个的值,它在内存中彼此相邻地排列所有的值。vector 只能储存相同类型的值。

新建vector

为了创建一个新的空 vector,可以调用 Vec::new 函数

fn main() {
    let _v: Vec<i32> = Vec::new();

}

注意这里我们增加了一个类型注解。因为没有向这个 vector 中插入任何值,Rust 并不知道想要储存什么类型的元素,尖括号中就是想要存储的类型。

在更实际的代码中,一旦插入值 Rust 就可以推断出想要存放的类型,所以很少会需要这些类型注解。更常见的做法是使用初始值来创建一个 Vec,而且为了方便 Rust 提供了 vec! 宏。这个宏会根据我们提供的值来创建一个新的 Vec

fn main() {
    let v1 = vec![1, 2, 3];
    println!("Hello, world!");
}

Rust 可以推断出 v 的类型是 Vec<i32>,因此类型注解就不是必须的。

更新vector

对于新建一个 vector 并向其增加元素,可以使用 push 方法

fn main() {
    let mut v = Vec::new();

    v.push(5);
    v.push(6);
    v.push(7);
    v.push(8);
    v.push(9);

}

如果想要能够改变它的值,必须使用 mut 关键字使其可变。放入其中的所有值都是 i32 类型的,而且 Rust 也根据数据做出如此判断,所以不需要 Vec<i32> 注解。

丢弃vector时也会丢弃所有元素

当 vector 被丢弃时,所有其内容也会被丢弃,这意味着这里它包含的整数将被清理。这可能看起来非常直观,不过一旦开始使用 vector 元素的引用,情况就变得有些复杂了。

读取vector的元素

访问 vector 中一个值的两种方式,索引语法或者 get 方法:

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    let third : &i32 = &v[2];                    // 索引
    println!("The third element is {}", third);

    // get方法
    match v.get(3) {
        Some(three) => println!("match The third element is {}", three),
        None => println!("There is no third element"),
    }
}

这里有两个需要注意的地方。首先,使用索引值 2 来获取第三个元素,索引是从 0 开始的。其次,这两个不同的获取第三个元素的方式分别为:使用 & 和 [] 返回一个引用;或者使用 get 方法以索引作为参数来返回一个 Option<&T>

Rust 有两个引用元素的方法的原因是程序可以选择如何处理当索引值在 vector 中没有对应值的情况。作为一个例子,让我们看看如果有一个有五个元素的 vector 接着尝试访问索引为 100 的元素时程序会如何处理。

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let does_not_exist = &v[100];
    let does_not_exist = v.get(100);
}

运行

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

 当运行这段代码,你会发现对于第一个 [] 方法,当引用一个不存在的元素时 Rust 会造成 panic。这个方法更适合当程序认为尝试访问超过 vector 结尾的元素是一个严重错误的情况,这时应该使程序崩溃。

当 get 方法被传递了一个数组外的索引时,它不会 panic 而是返回 None。当偶尔出现超过 vector 范围的访问属于正常情况的时候可以考虑使用它。接着你的代码可以有处理 Some(&element) 或 None 的逻辑。

一旦程序获取了一个有效的引用,借用检查器将会执行所有权和借用规则来确保 vector 内容的这个引用和任何其他引用保持有效。

在拥有 vector 中项的引用的同时向其增加一个元素

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let first = v[0];       // 不可变引用
    v.push(6);
    println!("the first element is: {}", first);
}

结果

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

不能这么做的原因是由于 vector 的工作方式:在 vector 的结尾增加新元素时,在没有足够空间将所有所有元素依次相邻存放的情况下,可能会要求分配新内存并将老的元素拷贝到新的空间中。这时,第一个元素的引用就指向了被释放的内存。借用规则阻止程序陷入这种状况。

还有些复杂

遍历vector中的元素

使用 for 循环来获取 i32 值的 vector 中的每一个元素的不可变引用并将其打印:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    for i in &v {
        println!("{}", i);
    }
}

也可以遍历可变 vector 的每一个元素的可变引用以便能改变他们

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    for i in &mut v {
        *i += 50;
    }
}

使用枚举来储存多种类型

枚举的成员都被定义为相同的枚举类型,所以当需要在 vector 中储存不同类型值时,可以定义并使用一个枚举!

假如我们想要从电子表格的一行中获取值,而这一行的有些列包含数字,有些包含浮点值,还有些是字符串。我们可以定义一个枚举,其成员会存放这些不同类型的值,同时所有这些枚举成员都会被当作相同类型,那个枚举的类型。接着可以创建一个储存枚举值的 vector,这样最终就能够储存不同类型的值了。

#[derive(Debug)]
enum SpreadsheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}


fn main() {


    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Float(10.12),
        SpreadsheetCell::Text(String::from("blue")),
        ];

        // 打印
        for item in row.iter() {
            println!("Enum item: {:?}", item);
        }
}

Rust 在编译时就必须准确的知道 vector 中类型的原因在于它需要知道储存每个元素到底需要多少内存。第二个好处是可以准确的知道这个 vector 中允许什么类型。如果 Rust 允许 vector 存放任意类型,那么当对 vector 元素执行操作时一个或多个类型的值就有可能会造成错误。

vector除了 push 之外还有一个 pop 方法,它会移除并返回 vector 的最后一个元素。

8.2 字符串

在集合章节中讨论字符串的原因是,字符串就是作为字节的集合外加一些方法实现的,当这些字节被解释为文本时,这些方法提供了实用的功能。

什么是字符串

在开始深入这些方面之前,我们需要讨论一下术语 字符串 的具体意义。Rust 的核心语言中只有一种字符串类型:str,字符串 slice,它通常以被借用的形式出现&str。第四章讲到了 字符串 slice:它们是一些储存在别处的 UTF-8 编码字符串数据的引用。比如字符串字面值被储存在程序的二进制输出中,字符串 slice 也是如此。

称作 String 的类型是由标准库提供的,而没有写进核心语言部分,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。当 Rustacean 们谈到 Rust 的 “字符串”时,它们通常指的是 String 和字符串 slice &str 类型,而不仅仅是其中之一。虽然本部分内容大多是关于 String 的,不过这两个类型在 Rust 标准库中都被广泛使用,String 和字符串 slice 都是 UTF-8 编码的。

新建字符串

很多 Vec 可用的操作在 String 中同样可用,从以 new 函数创建字符串开始

fn main() {
    let mut s = String::new();
}

这新建了一个叫做 s 的空的字符串,接着我们可以向其中装载数据。通常字符串会有初始数据,因为我们希望一开始就有这个字符串。为此,可以使用 to_string 方法,它能用于任何实现了 Display trait 的类型,字符串字面值也实现了它。

fn main() {
    let data = "hello world";
    let s = data.to_string();
    

    // 也可以直接用于字符串字面值
    let s = "hello world".to_string();
}

也可以使用 String::from 函数来从字符串字面值创建 String

fn main() {

    let s = String::from("value");

}

字符串是 UTF-8 编码的,所以可以包含任何可以正确编码的数据

fn main() {
    let hello = String::from("السلام عليكم");
    let hello = String::from("Dobrý den");
    let hello = String::from("Hello");
    let hello = String::from("שָׁלוֹם");
    let hello = String::from("नमस्ते");
    let hello = String::from("こんにちは");
    let hello = String::from("안녕하세요");
    let hello = String::from("你好");
    let hello = String::from("Olá");
    let hello = String::from("Здравствуйте");
    let hello = String::from("Hola");
}

更新字符串

String 的大小可以增加,其内容也可以改变,就像可以放入更多数据来改变 Vec 的内容一样。另外,可以方便的使用 + 运算符或 format! 宏来拼接 String 值。

使用push_str和push附加字符串

可以通过 push_str 方法来附加字符串 slice,从而使 String 变长

fn main() {
    let mut hello = String::from("foo");
    hello.push_str("bar");
    println!("{}", hello);

}

执行这两行代码之后,s 将会包含 foobarpush_str 方法采用字符串 slice,因为我们并不需要获取参数的所有权。

如果将 s2 的内容附加到 s1 之后,自身不能被使用就糟糕了。

fn main() {
    let mut s1 = String::from("hello");
    let s2 = "world";
    s1.push_str(s2);
    println!("s2 is {}", s2);

}

如果 push_str 方法获取了 s2 的所有权,就不能在最后一行打印出其值了。好在代码如我们期望那样工作!

push 方法被定义为获取一个单独的字符作为参数,并附加到 String 中。

fn main() {
    let mut s1 = String::from("hello");
    s1.push('L');

}

使用+运算符或format!宏拼接字符串

通常你会希望将两个已知的字符串合并在一起。一种办法是像这样使用 + 运算符

fn main() {
    let s1 = String::from("hello");
    let s2 = String::from("world");
    let s3 = s1 + &s2;
    // s1被移动了,不能使用
}

字符串 s3 将会包含 Helloworlds1 在相加后不再有效的原因,和使用 s2 的引用的原因,与使用 + 运算符时调用的函数签名有关。+ 运算符使用了 add 函数,这个函数签名看起来像这样:

fn add(self, s: &str) -> String {

首先,s2 使用了 &,意味着我们使用第二个字符串的 引用 与第一个字符串相加。这是因为 add 函数的 s 参数:只能将 &str 和 String 相加,不能将两个 String 值相加。不过等一下 —— 正如 add 的第二个参数所指定的,&s2 的类型是 &String 而不是 &str。那么为什么示例还能编译呢?

之所以能够在 add 调用中使用 &s2 是因为 &String 可以被 强转(coerced)成 &str。当add函数被调用时,Rust 使用了一个被称为 解引用强制多态(deref coercion)的技术,你可以将其理解为它把 &s2 变成了 &s2[..]

其次,可以发现签名中 add 获取了 self 的所有权,因为 self 没有 使用 &。这意味着示例中的 s1 的所有权将被移动到 add 调用中,之后就不再有效。所以虽然 let s3 = s1 + &s2; 看起来就像它会复制两个字符串并创建一个新的字符串,而实际上这个语句会获取 s1 的所有权,附加上从 s2 中拷贝的内容,并返回结果的所有权。换句话说,它看起来好像生成了很多拷贝,不过实际上并没有:这个实现比拷贝要更高效。

索引字符串

在很多语言中,通过索引来引用字符串中的单独字符是有效且常见的操作。然而在 Rust 中,如果你尝试使用索引语法访问 String 的一部分,会出现一个错误。

fn main() {
    let s1 = String::from("hello");
    let h = s1[0];
}

结果

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

错误和提示说明了全部问题:Rust 的字符串不支持索引。那么接下来的问题是,为什么不支持呢?为了回答这个问题,我们必须先聊一聊 Rust 是如何在内存中储存字符串的。

内部表现

String 是一个 Vec<u8> 的封装。

fn main() {
    let len1 = String::from("Hola").len();

    let len2 = String::from("Здравствуйте").len();
    println!("{}, {}", len1, len2);

}

在这里,len 的值是 4 ,这意味着储存字符串 “Hola” 的 Vec 的长度是四个字节:这里每一个字母的 UTF-8 编码都占用一个字节。当问及Здравствуйте这个字符是多长的时候有人可能会说是 12。然而,Rust 的回答是 24。这是使用 UTF-8 编码 “Здравствуйте” 所需要的字节数,这是因为每个 Unicode 标量值需要两个字节存储。

因为编码的原因,字符串使用索引时要特别谨慎。

遍历字符串的方法

如果你需要操作单独的 Unicode 标量值,最好的选择是使用 chars 方法。对 “नमस्ते” 调用 chars 方法会将其分开并返回六个 char 类型的值,接着就可以遍历其结果来访问每一个元素了:

fn main() {
    for c in "नमस्ते".chars() {
        println!("{}", c);
    }
}

结果

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

bytes 方法返回每一个原始字节,这可能会适合你的使用场景:

fn main() {
    for c in "नमस्ते".bytes() {
        println!("{}", c);
    }
}

 结果

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

总结

总而言之,字符串还是很复杂的。不同的语言选择了不同的向程序员展示其复杂性的方式。Rust 选择了以准确的方式处理 String 数据作为所有 Rust 程序的默认行为,这意味着程序员们必须更多的思考如何预先处理 UTF-8 数据。这种权衡取舍相比其他语言更多的暴露出了字符串的复杂性,不过也使你在开发生命周期后期免于处理涉及非 ASCII 字符的错误。

8.3 哈希map

HashMap<K, V> 类型储存了一个键类型 K 对应一个值类型 V 的映射。它通过一个 哈希函数hashing function)来实现映射,决定如何将键和值放入内存中。

新建一个哈希map

可以使用 new 创建一个空的 HashMap,并使用 insert 增加元素。

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();
    // 使用insert
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Green"), 50);

}

注意必须首先 use 标准库中集合部分的 HashMap。在这三个常用集合中,HashMap 是最不常用的,所以并没有被 prelude 自动引用。

像 vector 一样,哈希 map 将它们的数据储存在堆上,这个 HashMap 的键类型是 String 而值类型是 i32。类似于 vector,哈希 map 是同质的:所有的键必须是相同类型,值也必须都是相同类型。

另一个构建哈希 map 的方法是使用一个元组的 vector 的 collect 方法,其中每个元组包含一个键值对。

use std::collections::HashMap;
fn main() {
    let teams = vec![String::from("Blue"), String::from("Green")];
    let data = vec![10, 50];
    // 复杂
    let scores : HashMap<_, _> = teams.iter().zip(data.iter()).collect();

    for i in &scores {
        println!("{}, {}", i.0, i.1);
    }

}

这里 HashMap<_, _> 类型注解是必要的,因为可能 collect 很多不同的数据结构,而除非显式指定否则 Rust 无从得知你需要的类型。但是对于键和值的类型参数来说,可以使用下划线占位,而 Rust 能够根据 vector 中数据的类型推断出 HashMap 所包含的类型。

哈希map和所有权

对于像 i32 这样的实现了 Copy trait 的类型,其值可以拷贝进哈希 map。对于像 String 这样拥有所有权的值,其值将被移动而哈希 map 会成为这些值的所有者。

use std::collections::HashMap;
fn main() {
    
    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 和 field_value 不再有效,

    println!("{}, {}", field_name, field_value);
}

结果

【Rust】Rust学习 第八章常见集合,Rust,rust,学习,开发语言,keep studying,后端,笔记

访问哈希map中的值

可以通过 get 方法并提供对应的键来从哈希 map 中获取值

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let team_name = String::from("Blue");
    //使用get
    let score = scores.get(&team_name);
    println!("{:?}", score);
}

可以使用与 vector 类似的方式来遍历哈希 map 中的每一个键值对,也就是 for 循环:

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    for (k, v) in &scores {
        println!("{}, {}", k, v)
    }
}

这样也可以

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    for item in &scores {
        println!("{}, {}", item.0, item.1)
    }
}

更新哈希map

尽管键值对的数量是可以增长的,不过任何时候,每个键只能关联一个值。当我们想要改变哈希 map 中的数据时,必须决定如何处理一个键已经有值了的情况。可以选择完全无视旧值并用新值代替旧值。可以选择保留旧值而忽略新值,并只在键 没有 对应值时增加新值。或者可以结合新旧两值。

覆盖一个值

如果我们插入了一个键值对,接着用相同的键插入一个不同的值,与这个键相关联的旧值将被替换。

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Blue"), 50);    // 后面出現的覆蓋前面出現的
    println!("{:?}", scores);
}

只在键没有对应值时插入

经常会检查某个特定的键是否有值,如果没有就插入一个值。

use std::collections::HashMap;
fn main() {
    let mut scores = HashMap::new();

    scores.insert(String::from("Green"), 10);
    scores.insert(String::from("Blue"), 50);    // 后面出現的覆蓋前面出現的

    scores.entry(String::from("Green")).or_insert(90);    // Green不存在就插入,存在就不插入

    println!("{:?}", scores);
}

Entry 的 or_insert 方法在键对应的值存在时就返回这个值的 Entry,如果不存在则将参数作为新值插入并返回修改过的 Entry

根据旧值更新一个值

另一个常见的哈希 map 的应用场景是找到一个键对应的值并根据旧的值更新它。

use std::collections::HashMap;
fn main() {
    // 統計單詞出現的次數
    let text = "hello world wonderful world";
    let mut map = HashMap::new();

    for word in text.split_ascii_whitespace() {
        let count = map.entry(word).or_insert(0);
        *count += 1;
    }
    println!("{:?}", map);
}

这会打印出 {"world": 2, "hello": 1, "wonderful": 1}or_insert 方法事实上会返回这个键的值的一个可变引用(&mut V)。这里我们将这个可变引用储存在 count 变量中,所以为了赋值必须首先使用星号(*)解引用 count。这个可变引用在 for 循环的结尾离开作用域,这样所有这些改变都是安全的并符合借用规则。

哈希函数

HashMap 默认使用一种 “密码学安全的”(“cryptographically strong” )1 哈希函数,它可以抵抗拒绝服务(Denial of Service, DoS)攻击。然而这并不是可用的最快的算法,不过为了更高的安全性值得付出一些性能的代价。如果性能监测显示此哈希函数非常慢,以致于你无法接受,你可以指定一个不同的 hasher 来切换为其它函数。hasher 是一个实现了 BuildHasher trait 的类型。

参考:常见集合 - Rust 程序设计语言 简体中文版 (bootcss.com)文章来源地址https://www.toymoban.com/news/detail-640539.html

到了这里,关于【Rust】Rust学习 第八章常见集合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Rust 语言常见的一些概念(上)

    目录 1、变量的可变性 常量  隐藏 2、数据类型 2.1 标量类型 整型 浮点型 数值运算 布尔型 字符类型 复合类型 元组类型 数组类型 变量默认是不可改变的(immutable)。这是 Rust 提供给你的众多优势之一,让你得以充分利用 Rust 提供的安全性和简单并发性来编写代码。不过,你

    2024年02月06日
    浏览(34)
  • 第八章 常见Linux命令

    1 了解Linux帮助类命令 2 熟悉开关机命令 3 熟练文件目录类命令 4 熟悉时间日期类命令 5 熟悉用户管理命令 6 熟悉组管理命令 7 熟练文件权限命令 8 熟悉搜索查找类命令 9 熟练压缩和解压缩命令 10 熟悉磁盘分区类命令 11 熟练进程线程类命令 12 了解系统定时任务命令 man获取帮

    2024年02月11日
    浏览(36)
  • Rust语言从入门到入坑——(2)Rust在windows上搭建开发环境

    开始搭建一个适合在windows上运行的Rust环境。 Rust支持的程序语言很多:可详见官网介绍 本文章主要是在windowns下搭建开发环境 首先,需要安装最新版的 Rust 编译工具和 Visual Studio Code。 Rust 编译工具:https://www.rust-lang.org/zh-CN/tools/install Visual Studio Code:https://code.visualstudio.com

    2024年02月09日
    浏览(50)
  • 【Rust】Rust学习 第十三章Rust 中的函数式语言功能:迭代器与闭包

    Rust 的设计灵感来源于很多现存的语言和技术。其中一个显著的影响就是  函数式编程 ( functional programming )。函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将函数赋值给变量以供之后执行等等。 更具体的,我们将要涉及: 闭包 ( Closures ),一个可以储

    2024年02月12日
    浏览(51)
  • 简单对比Java、Python、Go、Rust等常见语言计算斐波拉契数的性能

    最近简单学了下Rust,以我这种菜鸟水平,没感受到什么安全、性能什么方面的优势,只觉得概念太多,编译各种报错。暂时也写不出来什么玩法,索性对比下各种学过的语言的性能。部分语言很早之前学过,很久不用就忘了,所以是用GPT写的。但运行逻辑很简单,所以应该没

    2024年03月16日
    浏览(49)
  • 考研C语言第八章

    这个东西看着像数据库里面属性的定义,也像java里面的类的定义 关于结构体里面scanf读取输入的数据,并进行相关的存储, 这里面字符串就像之前的,取数据时可以和前面的不加空格,可以不加取地址符号 (但是为了好记和规范,建议直接所有的一视同仁) 就想数据库在输

    2024年02月10日
    浏览(35)
  • Rust软件外包开发语言的特点

    Rust 是一种系统级编程语言,强调性能、安全性和并发性的编程语言,适用于广泛的应用领域,特别是那些需要高度可靠性和高性能的场景。下面和大家分享 Rust 语言的一些主要特点以及适用的场合,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公

    2024年02月12日
    浏览(47)
  • 『C语言初阶』第八章 -结构体

    🔥 博客主页 : 小羊失眠啦. 🔖 系列专栏 : C语言 🌥️ 每日语录 : 相信自己,比谁都棒。 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 今天小羊又来给铁汁们分享关

    2024年02月12日
    浏览(33)
  • 自然语言处理: 第八章chatGPT的搭建

    Transformer 大模型家族可以分成三类, 至于三者的区别可以参考上一章: Encoder-only, Decoder-only, 只需要Pre_train Encoder-decoder , 可以在一些任务上无需进行fine_tune 必须要在下游任务进行微调比如Bert , Bart 。 T5 这种无需要微调就能完成一些任务 。最后GPT从3开始,只需要预训练就能适

    2024年02月12日
    浏览(42)
  • 《汇编语言》王爽(第四版)第八章 实验7

    文章目录 前言 一、题目 二、分析 1.内存分配情况 2.数据结构分析 3.实现思路 (1)设置段寄存器 (2)复制“年份”数据 (3)复制“年总收入”数据 (4)复制“雇员人数”数据 (5)计算“人均收入” 三、代码 1.实现代码 2.优化代码 3.最终代码 总结 王爽老师《汇编语言》

    2024年02月04日
    浏览(68)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包