• 下一代智能合约编程语言Move(四)


    背景

    之前的文章我们已经介绍了Move的模块和函数,接下来将会介绍一些Move的特性。

    结构体

    结构体是用户自定义的拥有复杂数据的数据类型,它可以简单理解为一个key——value形式的存储器,key时存储数据的名字而value是其存储的值。

    结构体的定义

    结构体只能在模块里定义,一struct关键字开头,之后时名字和双括号,双括号里面是是定义:

    struct Name {
      FIELD1: TYPE1,
      FIELD@: TYPE2,
      ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以下就是结构体定义的例子:

    module M {
      struct Empty{}
    
      struct MyStruct{
        field1: address,
        field2: bool,
        field3: Empty
      }
    
      struct Example {
        field1: u8,
        field2: address,
        field3: u64,
        field4: bool,
        field5: bool,
    
        field5: MyStruct
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    需要注意的是每一个定义的结构体都会变成一个新的类型,这个类型可以桶模块访问,如M::MyStruct。

    递归定义在Move是不允许的,例如以下代码编译会报错:

    struct MyStruct{
        field5: MyStruct
      }
    
    • 1
    • 2
    • 3
    结构体的使用

    我们可以通过创建实例来使用结构体,可以通过它的定义来创建实例:

    module Country {
      struct Country {
        id: u8,
        population: u64
      }
    
      public fun new_country(c_id: u8, c_population: u64): Country {
        let country = Country {
          id: c_id,
          population: c_population
        };
        country
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Move还允许使用更简洁的方式创建实例:

    // ...
    public fun new_country(id: u8, population: u64): Country {
        // id matches id: u8 field
        // population matches population field
        Country {
            id,
            population
        }
    
        // or even in one line: Country { id, population }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    访问结构体的属性

    只有模块内部才能访问结构体的属性,对于模块外部,结构体的属性是不可见的:

    // ...
    public fun get_country_population(country: Country): u64 {
        country.population // .
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    结构结构体

    可以通过let = 去解构一个结构体

    module Country {
    
        // ...
    
        // we'll return values of this struct outside
        public fun destroy(country: Country): (u8, u64) {
    
            // variables must match struct fields
            // all struct fields must be specified
            let Country { id, population } = country;
    
            // after destruction country is dropped
            // but its fields are now variables and
            // can be used
            (id, population)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    需要注意的是未使用的变量在Move中是被禁止的,如果解构结构体又不需要使用其属性,需要使用下划线:

    module Country {
        // ...
    
        public fun destroy(country: Country) {
    
            // this way you destroy struct and don't create unused variables
            let Country { id: _, population: _ } = country;
    
            // or take only id and don't init `population` variable
            // let Country { id, population: _ } = country;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    之前提到外部的模块是无法直接访问结构体的属性的,所以为了外部模块能够访问定义的结构体的属性,需要提供相关的访问函数:

    module Country {
    
        struct Country {
            id: u8,
            population: u64
        }
    
        public fun new_country(id: u8, population: u64): Country {
            Country {
                id, population
            }
        }
    
        // don't forget to make these methods public!
        public fun id(country: &Country): u8 {
            country.id
        }
    
        // don't mind ampersand here for now. you'll learn why it's 
        // put here in references chapter 
        public fun population(country: &Country): u64 {
            country.population
        }
    
        // ... fun destroy ... 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Abilities

    Move有一个非常灵活且可高度定制化的类型系统,每一个类型都可以被赋予四种能力去决定数据怎么被使用、删除活存储,这四种能力如下:

    • Copy-可以被复制

    • Drop-可以在结尾被删除

    • Key-可以被全局存储设置为key

    • Store-可以被全局存储

      这篇文章会介绍Copy和Drop的能力,至于Key和Store能力在之后的文章详细介绍。在定义结构体的时候可以设置这四种能力:

      module Library {
      struct Book has store, copy, drop {
        year: u64
      }
      
      struct Storage has {
        books: vector
      }
      
      struct Empty{}
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    }

    如果没有设置这几种属性会怎么样呢:
    
    • 1

    odule Country {
    struct Country {
    id: u8,
    population: u64
    }

    public fun new_country(id: u8, population: u64) {
    Country(id, population)
    }
    }

      script {
      use {{sender}}::Country;

      fun main() {
      Country::new_country(1, 1000000);
      }
      }

      我嘛在Country中定义了一个结构体,然后通过一个方法暴露给外部,然后在外部调用这个方法来获取数据,但是返回值没有被使用,由于我们没有给这个结构体设置Drop属性,这时候不会自动丢弃返回值,会报错
      
      • 1

      error:
      ┌── scripts/main.move:5:9 ───

      5 │ Country::new_country(1, 1000000);
      │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot ignore values without the ‘drop’ ability. The value must be used

      #### Drop
      我们可以通过has Drop给结构体设置Drop能力
      
      • 1
      • 2

      module Country {
      struct Country has drop { // has
      id: u8,
      population: u64
      }
      // …
      }

      当我们设置了Drop能力,脚本就能运行了:
      
      • 1

      script {
      use {{sender}}::Country;

      fun main() {
          Country::new_country(1, 1000000); // value is dropped
      }   
      
      • 1
      • 2
      • 3

      }

      > Drop只定义Drop的能力,解构不需要Drop能力。
      
      #### Copy
      我们已经学习了如何创建一个Country实例以及丢弃它,那么我们该如何实现拷贝呢,Move提供来copy关键字来实现拷贝,前提是需要已经赋予结构体copy能力。
      
      • 1
      • 2
      • 3
      • 4

      module Country {
      struct Country has drop, copy { // see comma here!
      id: u8,
      population: u64
      }
      // …
      }

        script {
        use {{sender}}::Country;

        fun main() {
            let country = Country::new_country(1, 1000000);
            let _ = copy country;
        }   
        
        • 1
        • 2
        • 3
        • 4

        }

        ### 最后,这篇文章我们主要介绍了Move的结构体与类型系统的四种能力,更多文章可以关注QStack。
        
        
        
        
        
        
        
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
      • 相关阅读:
        Spring Boot : ORM 框架 JPA 与连接池 Hikari
        免费SaaS敏捷管理工具
        论文解读:Rectifying the Shortcut Learning of Background for Few-Shot Learning
        libevent库
        Spring IOC理论
        vb圣经加注释
        无代码开发成员入门教程
        面向交通运输的计算机视觉和深度学习2
        【畅购商城】购物车模块之修改购物车以及结算
        【gcc】RtpTransportControllerSend学习笔记 2
      • 原文地址:https://blog.csdn.net/QStack/article/details/128054278