下一代的智能合约编程语言Move(六)

前言

世界杯终于结束了,也要慢慢调回中国的作息了,不能再继续划水了,最近也看到Aptos在2月份将会在韩国举行黑客松,这也是一个练手的好机会,还是要赶紧学完Move,今天这篇文章将会主要介绍Move中的泛型,泛型对于Move来说十分重要,其令Move在区块链世界的地位十分特殊,也是Move灵活性的源泉。

泛型是对于具体类型和属性的抽象存在,从应用的角度来说,使用泛型可以通过写一个函数用于其他所有类型,它们也可以被称为这个模版,因为这个函数可以被当作模版处理其他任何类型,在Move中泛型可以用于结构体和函数。

结构体的定义

如果我们想创建一个Box的结构体,里面包含了一个u64的值,我们之前的做法是这样的:

module M {
  struct Box {
    value: u8
  }
}

显然这个Box只能包含一个u64的值,但是如果我嘛需要一个包含u8或者bool类型的Box,我们该怎么做呢,创建一个Box1?或者Box2?当需要的类型越来越多时这种方法显的十分的繁琐,我们可以通过泛型来简化这个过程。

module M {
  struct Box<T> {
    value: T
  }
}

可以看到在结构体旁边我们使用了'',其中的T就是我们在结构体里使用的类型,在结构体里我们可以将T当作常规类型使用,实际上T并不是一个存在的类型,其只是其他任何类型的占位符。

函数签名

现在我们为之前的结构体创建一个构造函数,首先使用之前熟悉的u64,最后的结果如下:

module M {
  struct Box<T> {
    value: T
  }

  //我们使用了u64替换了T意味着我们将会使用带有u64的结构体
  public fun create_box(value: u64): Box<u64> {
    Box<u64>{ value }
  }
}

如上所示我们通过用u64替换T指定Box是带有u64的Box,但是有时候我们希望获取带有u8或者bool或者其他类型的Box,我们该怎么做呢,当然还是使用泛型,通过在函数定义时使用泛型,我们就可以实现这种效果,代码如下:

module M {
  struct Box<T> {
    value: T
  }

  public fun create_box<T>(value: T): Box<T> {
    Box<T>{ value }
  }
}

正如我们在结构体中使用泛型,在函数定义中使用泛型也是在函数名后加上'',当函数定义好后我们又该如何通过指定类型来调用函数呢。

script {
  use {{sender}}::Storage;
  use 0x1::Debug

  fun main() {
    
    //我们将会获得一个带有bool类型的Box
    let bool_box = Storage::create_box<bool>(true);
    let bool_val = Storage::value(&bool_box)

    assert(bool_val, 0);

    //我们也可以同样获取integer的Box
    let u64_box = Storage::create_box<u64>(1000000);
    let _ = Storage::value(&u64_box);

  }
}

以上我们创建来带有u64和bool类型的Box,我们也可以使用泛型定义更加复杂的类型。

能力检查

在之前的文章中我们已经学过了Move中的四大能力,这在泛型中也是相同的。

fun name<T: copy>() {} // 只可以复制
fun name<T: copy + drop>() {} // 可以复制和丢弃
fun name<T: key + store + drop + copy>() {} // 四种能力都具备

在结构体中也是一样的

struct name<T: copy + drop> { value: T } // T可以复制和丢弃
struct name<T: store> { value: T } // T 可以全局存储

+的这种用法可能咋看起来有点不大好理解,这也是+关键字列表的唯一用法。

其常规用法如下:

module Storage {

    // box的contents可以被存储
    struct Box<T: store> has key, store {
        content: T
    }
}

需要注意的是泛型类型必须要有其容器(如Box)拥有的所有能力(key除外)。其逻辑也很好理解,拥有copy能力的结构体,其内部的内容也必须要拥有copy能力,否则其就不能认为拥有copy能力。编译器无法发现这个问题,但是当你使用的时候会出错。例子如下

module Storage {
    // 结构体无法复制和丢弃
    struct Error {}
    
    // 没有明确限制
    struct Box<T> has copy, drop {
        contents: T
    }

    // 这个方法创建来一个没有复制和丢弃能力内容的Box
    public fun create_box(): Box<Error> {
        Box { contents: Error {} }
    }
}

这时编译不会有问题,但是当我们使用时

script {
    fun main() {
        {{sender}}::Storage::create_box() // value 被创建然后丢弃
    }   
}

会发生以下报错

   ┌── scripts/main.move:5:9 ───
   │
 5 │   Storage::create_box();
   │   ^^^^^^^^^^^^^^^^^^^^^ Cannot ignore values without the 'drop' ability. The value must be used
   │

这个错误发生是因为内部的值没有drop能力,所以外部的容器也会被限制没有drop能力。

安全的结构体的定义方式如下:

struct Box<T: copy + drop> has copy, drop {
    contents: T
}
多个类型的泛型

多个类型的泛型与单个泛型类似,不同的是不同泛型使用逗号隔开。

module Storage {

    struct Box<T> {
        value: T
    }

    struct Shelf<T1, T2> {
        box_1: Box<T1>,
        box_2: Box<T2>
    }

    public fun create_shelf<Type1, Type2>(
        box_1: Box<Type1>,
        box_2: Box<Type2>
    ): Shelf<Type1, Type2> {
        Shelf {
            box_1,
            box_2
        }
    }
}

多个泛型的使用也类似

script {
    use {{sender}}::Storage;

    fun main() {
        let b1 = Storage::create_box<u64>(100);
        let b2 = Storage::create_box<u64>(200);

        let _ = Storage::create_shelf<u64, u64>(b1, b2);
    }
}

需要注意的是不是所有制定类型的泛型都要使用,例子如下

module Storage {

    struct Abroad {}
    struct Local {}

    struct Box<T, Destination> {
        value: T
    }

    public fun create_box<T, Dest>(value: T): Box<T, Dest> {
        Box { value }
    }
}



script {
    use {{sender}}::Storage;

    fun main() {
        // value will be of type Storage::Box<bool>
        let _ = Storage::create_box<bool, Storage::Abroad>(true);
        let _ = Storage::create_box<u64, Storage::Abroad>(1000);

        let _ = Storage::create_box<u128, Storage::Local>(1000);
        let _ = Storage::create_box<address, Storage::Local>(0x1);

        // or even u64 destination!
        let _ = Storage::create_box<address, u64>(0x1);
    }
}

最后

这篇文章主要介绍了Move中泛型。更多文章可以关注微信公众号QStack。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值