# Move高级进阶--泛型编程 **Published by:** [shaneson.eth](https://paragraph.com/@shaneson-eth/) **Published on:** 2022-08-24 **URL:** https://paragraph.com/@shaneson-eth/move ## Content Move语言里,最高级和最难掌握的用法是泛型。它是 Move 灵活性的重要来源,融合C++的泛型编程的思想。与Solidity对比,泛型的功能可以让工厂合约更容易实现合约模版,提供了非常强的灵活性。本文会介绍,我在学习Move泛型编程时的要点。结构体中的泛型通过泛型的定义,我们可以使得value的值可以是任何的类型T。module Storage { struct Box<T> { value: T } } 函数中的泛型我以create Box为例,构造一个模版方法和get 方法。module ShanesonStudy::Generics { struct Box<T> has drop, copy, key { value: T } public fun create_box<T>(value: T): Box<T> { Box<T> { value } } public fun value<T: copy> (box: &Box<T>): T { *&box.value } } create_box的模版参数为T,假设传入的值为value,类型为T。那么语法就是create_box (value: T),返回值是Box。这里值得注意的是,临时变量是要被丢弃的。所以,struct Box要有Drop权限。 方法value看起来非常复杂,意思就是:“就是把Box里面的value拷贝出来一份”。 测试方法: module ShanesonStudy::GenericsTest { use ShanesonStudy::Generics as G; use std::debug as D; #[test] public entry fun create_box_test() { let _box = G::create_box(true); let _box_val = G::value(&_box); D::print (&_box_val); assert!(_box_val, 0); let u64_box = G::create_box (1000000); let _u64_box_result = G::value(&u64_box); D::print(&_u64_box_result); } } Result: Abilities限制符 泛型里的模版参数也是有限制的,所以可以在模版定义的时候定义它的权限:“copy + drop” fun name() {} // allow only values that can be copied fun name() {} // values can be copied and dropped fun name() {} // all 4 abilities are present struct name { value: T } // T can be copied and dropped struct name { value: T } // T can be stored in global storage 注意,尽可能使泛型参数的限制符和结构体本身的abilities显示的保持一致。+号很少使用,但是这里确实是+号来拼接限制符。 所以下面这种定义的方法更安全: // we add parent's constraints // now inner type MUST be copyable and droppable struct Box has copy, drop { contents: T } 多类型限制符 我们也可以在泛型中使用多个类型,像使用单个类型一样,把多个类型放在尖括号中,并用逗号分隔。我们来试着添加一个新类型Shelf,它将容纳两个不同类型的Box。 module Storage { struct Box { value: T } struct Shelf { box_1: Box, box_2: Box } public fun create_shelf( box_1: Box, box_2: Box ): Shelf { Shelf { box_1, box_2 } } } Shelf的类型参数需要与结构体字段定义中的类型顺序相匹配,而泛型中的类型参数的名称则无需相同,选择合适的名称即可。正是因为每种类型参数仅仅在其作用域范围内有效,所以无需使用相同的名字。 多类型泛型的使用与单类型泛型相同: script { use {{sender}}::Storage; fun main() { let b1 = Storage::create_box(100); let b2 = Storage::create_box(200); // you can use any types - so same ones are also valid let _ = Storage::create_shelf(b1, b2); } } 并非泛型中指定的每种类型参数都必须被使用。看这个例子: module Storage { // these two types will be used to mark // where box will be sent when it's taken from shelf struct Abroad {} struct Local {} // modified Box will have target property struct Box { value: T } public fun create_box(value: T): Box { Box { value } } } 也可以在脚本中使用 : script { use {{sender}}::Storage; fun main() { // value will be of type Storage::Box let _ = Storage::create_box(true); let _ = Storage::create_box(1000); let _ = Storage::create_box(1000); let _ = Storage::create_box(0x1); // or even u64 destination! let _ = Storage::create_box(0x1); } } ## Publication Information - [shaneson.eth](https://paragraph.com/@shaneson-eth/): Publication homepage - [All Posts](https://paragraph.com/@shaneson-eth/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@shaneson-eth): Subscribe to updates