{"content":{"title":"14.轻松入门Sui Move:  集合（上）","body":"这一章我们将讲解如何保存数据的集合。说到数据的集合首先想到的肯定是数组，Move标准库给我们提供了vector模块以支持数组类型。\r\n\r\n### 数组\r\n\r\nvector是一个可变长度的，任意类型的容器。跟其他语言的数组一样，使用索引访问，索引从0开始。\r\n\r\n如何使用数组，在结构体章节讲解String类型讲过：\r\n\r\n```rust\r\n//struct <type name> <has abilities>\r\nstruct String has copy, drop, store {\r\n    bytes: vector<u8>,\r\n}\r\n```\r\n\r\nString类型本质就是一个字节数组。vector使用了泛型来支持任何类型，所以在使用它的时候需要指定类型参数。\r\n\r\n###### 创建数组\r\n\r\n我们可以使用empty方法，创建一个空数组\r\n\r\n```rust\r\nlet arr = vector::empty<u64>();\r\n```\r\n\r\n或者创建一个长度为1的数组\r\n\r\n```rust\r\nlet arr = vector::singleton<u64>(12);\r\n```\r\n\r\n也可以使用[]创建数组\r\n\r\n```rust\r\nlet arr = vector<u64>[1,2,3,4];\r\n```\r\n\r\n###### 添加元素\r\n\r\n- 在数组尾部插入一个元素\r\n\r\n  ```rust\r\n  vector::push_back<u64>(&mut arr, 67);\r\n  ```\r\n\r\n- 在数组指定位置插入一个元素\r\n\r\n  ```rust\r\n  //在数组arr的第三个元素位置插入100\r\n  vector::insert<u64>(&mut arr, 100, 2);\r\n  ```\r\n\r\n  insert函数第三个参数，用于指定插入位置。如果插入位置已经超过数组长度将会报错；等于数组长度则在数组末尾插入元素；小于数组长度该位置的元素及后续元素均往后移一位。注意这里不是替换原位置元素，而是插入。\r\n\r\n- 合并两个数组\r\n\r\n  ```rust\r\n  public fun append<Element>(lhs: &mut vector<Element>, mut other: vector<Element>) \r\n  ```\r\n\r\n  将other数组合并到lhs数组。被合并数组必须传值，合并数组则传可变引用。\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  \r\n  let mut arr2 = vector::singleton<u64>(3);\r\n  vector::push_back(&mut arr2, 4);\r\n  \r\n  vector::append(&mut arr2, arr1);\r\n  print(&arr2);\r\n  //打印结果：[ 3, 4, 1, 2, 3 ]\r\n  ```\r\n\r\n  合并完的数据，顺序是：lhs数组、other数组。如果有重复的值也会保留。\r\n\r\n###### 获取元素\r\n\r\n- 弹出数组尾部元素\r\n\r\n  ```rust\r\n  assert!(!vector::is_empty<u64>(&arr), 1);\r\n  let item = vector::pop_back<u64>(&mut arr);\r\n  ```\r\n\r\n  注意，弹出后返回的是元素值，数组中不再包含该值，长度-1。在调用pop_back之前请确保数组不为空否则将会报错。\r\n\r\n- 获取指定位置元素\r\n\r\n  与弹出不同，borrow和borrow_mut只是获取元素引用，并没有从数组中取出元素。\r\n\r\n  borrow是不可变引用，只用于读；如果要修改元素则使用borrow_mut\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  //可变引用第一个元素\r\n  let item = vector::borrow_mut(&mut arr1, 0);\r\n  *item = 2;\r\n  \r\n  print(&arr1);\r\n  //输出结果：[ 2, 2, 3 ]\r\n  ```\r\n\r\n###### 交换位置\r\n\r\n- 反转数组\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  \r\n  vector::reverse(&mut arr1);\r\n  \r\n  print(&arr1);\r\n  //输出结果：[ 3, 2, 1 ]\r\n  ```\r\n\r\n- 两个位置互换\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  //位置2和3交换值\r\n  vector::swap(&mut arr1, 1, 2);\r\n  \r\n  print(&arr1);\r\n  //输入结果：[1, 3, 2]\r\n  ```\r\n\r\n###### 删除元素\r\n\r\n- 弹出末尾元素\r\n\r\n  - 这个在上面已经讲过，不再赘述\r\n\r\n- 删除指定位置元素\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  \r\n  vector::remove(&mut arr1, 1);\r\n  \r\n  print(&arr1);\r\n  //输出结果：[1,3]\r\n  ```\r\n\r\n  注意：在删除指定位置的元素后，后续元素会自动前移一位。\r\n\r\n- 删除并使用末尾元素填充\r\n\r\n  ```rust\r\n  let mut arr1 = vector::singleton<u64>(1);\r\n  vector::push_back(&mut arr1, 2);\r\n  vector::push_back(&mut arr1, 3);\r\n  \r\n  vector::swap_remove(&mut arr1, 0);\r\n  \r\n  print(&arr1);\r\n  //输出结果：[3, 2]\r\n  ```\r\n\r\n  被删除的位置使用末尾元素填充，省去了前移元素的时间，如果元素顺序不重要，优选此方法。\r\n\r\n- 删除空数组\r\n\r\n  ```rust\r\n  assert!(is_empty(&arr1), 1);\r\n  vector::destroy_empty(arr1);\r\n  ```\r\n\r\n  注意，请在调用destroy_empty之前确保数组是空的，否则会导致报错\r\n\r\n###### 其他\r\n\r\n- 获取数组长度\r\n\r\n  ```rust\r\n  let len = vector::length(&arr1);\r\n  ```\r\n\r\n- 判断数组是否为空\r\n\r\n  ```rust\r\n  assert!(vector::is_empty(&arr1), 1);\r\n  ```\r\n\r\n- 根据值获取元素位置\r\n\r\n  ```rust\r\n  public fun index_of<Element>(v: &vector<Element>, e: &Element): (bool, u64) \r\n  ```\r\n\r\n  ```rust\r\n  let (exsits, index) = vector::index_of<u64>(&arr1, &item);\r\n  ```\r\n\r\n  注意第二个参数是传入元素的引用不是本身.返回两个字段,第一个代表是否存在,第二个代表元素位置.\r\n\r\n- 是否包含某元素\r\n\r\n```rust\r\nlet item: u64 = 2;\r\nlet exists = vector::contains<u64>(&arr1, &item);\r\n```\r\n\r\nvector模块具有丰富的函数,利用pop_back和push_back可以轻松实现栈, 利用insert和remove也能轻松实现队列.\r\n\r\n### 优先级队列\r\n\r\n优先级队列使用最大堆排序方法来对优先级进行排序.优先级高的先出列.如果我们需要有序的数据集合,就可以使用优先级队列.\r\n\r\n最大堆是二叉树并且每个节点的值都大于或等于其子节点.也就是说根节点就是堆中最大值.最大堆排序的平均时间复杂度是O(nlogn)是一种比较优秀的排序方法.\r\n\r\n我们以学生成绩排名为例来介绍优先级队列的功能,创建一个学生结构体和一个学校期末报告结构体.期末报告结构体负责保存学生信息和成绩,并按照成绩从高到低输入分数和学生的信息.\r\n\r\n```rust\r\npublic struct Student has drop,store {\r\n    name: String,\r\n    score: u64,\r\n}\r\npublic struct SchoolReport has drop{\r\n    report: PriorityQueue<Student>,\r\n}\r\n```\r\n\r\n期末报告report字段,类型就是优先级队列.这里需要注意的是,Student结构体作为优先级队列中实体的值,必须要有drop和store能力.\r\n\r\n期末出成绩后,往优先级队列中塞入成绩\r\n\r\n```rust\r\npublic fun new(): SchoolReport{\r\n    let student1 = Student{\r\n        name: string::utf8(b\"hanmeimei\"),\r\n        score: 89,\r\n    }; \r\n    let student2 = Student{\r\n        name: string::utf8(b\"lilei\"),\r\n        score: 97,\r\n    }; \r\n    let p = vector<u64>[89,97]; \r\n    let students = vector<Student>[student1, student2]; \r\n\r\n    SchoolReport{\r\n        report: priority_queue::new<Student>(priority_queue::create_entries<Student>(p, students)),\r\n    }\r\n}\r\n```\r\n\r\n在创建优先级队列之前,我们需要调用create_entries方法创建实体数组.\r\n\r\n塞入一个成绩为70分的学生:\r\n\r\n```rust\r\npublic fun add_student(sr: &mut SchoolReport) {\r\n    let student1 = Student{\r\n        name: string::utf8(b\"libai\"),\r\n        score: 70,\r\n    }; \r\n    priority_queue::insert<Student>(&mut sr.report, 70, student1);       \r\n}\r\n```\r\n\r\n按照成绩从高到低排序并输出\r\n\r\n```rust\r\npublic fun rank(sr: &mut SchoolReport) {\r\n    while(true) {\r\n        let (p, student) = priority_queue::pop_max<Student>(&mut sr.report);\r\n\r\n        print(&p);\r\n        print(&student.name);\r\n    }\r\n}\r\n```\r\n\r\npop_max每次一定会输出堆内最大值,多次调用直到堆内无数据,即可实现对分数的排序.\r\n\r\n\r\n\r\n了解更多Sui Move内容：\r\n\r\n- telegram: t.me/move_cn\r\n- QQ群: 79489587"},"author":{"user":"https://learnblockchain.cn/people/18898","address":"0x4eB04f04B97c383139e3890a486eC83c1F30ae1B"},"history":null,"timestamp":1716996216,"version":1}