Solidity基础四

あなたもきっと、誰かの奇跡 (你也一定会是某个人的奇迹)

目录

一、Solidity的结构体

1.结构体的实例化 

2.结构体的基本使用

访问和修改结构体成员

3.结构体的修饰符 

二、Solidity的映射

1.映射的基本使用

查询和修改某个value值

三、Solidity的枚举 

四、数组、结构体、映射的直接相互嵌套

1.没有数组嵌套数组

2.数组嵌套结构体

3.没有数组嵌套映射

4.结构体嵌套数组

5.结构体嵌套结构体

6.结构体嵌套映射

7.映射嵌套数组

8.映射嵌套结构体

9.映射嵌套映射

10、重要说明(间接嵌套)

五、关于枚举的嵌套


  

一、Solidity的结构体

结构体是一个引用数据类型,用于表示复合型数据

在结构体里面的数据我们称之为成员

结构体可以任何数据类型作为体内的成员,但是不能内部包含自身结构体,也就是不能在自己的结构体中写自己的结构体

结构体可以多次实例化,且各个实例化互不影响

关键字:struct

 

定义结构体格式:

struct 结构体名 {

成员1;

成员2;

成员3;

```````````

结构体的可见性:

关于可见性,目前只支持internal,所以结构体只能在合约内部和子合约内使用。包含结构体的函数必须显性声明为internal

因此结构体里面的成员也是internal,不能再定义权限修饰符了

1.结构体的实例化 

结构体创建后其实是一个模板类似于java中的类,对其实例化以后,相当于拿了这个模板去使用,同一个结构体不同实例化互不影响,自己存储在自己对应的实例化内存中,类似于java的对象

实例化格式:

结构体名  修饰符 实例化结构体名

温馨提示:结构体实例化之后,会给实例化结构体内部数据赋予一个初始值

结构体实例化后整体赋值:

实例化名 = 结构体名(值1,值2,·····)   

注意:上下这两种方式是整体赋值必须全部赋值,否则报错

实例化结构体并初始化格式:

结构体名 修饰符 实例化名 = 结构体名(值1,值2,·····)    这个要按成员顺序赋值

结构体名 修饰符 实例化名 = 结构体名({ 成员:值,成员:值,···})   这个可以不按照顺序赋值

2.结构体的基本使用

访问和修改结构体成员

访问结构体成员格式:

实例化结构体名.成员

修改结构体成员格式:

实例化结构体名.成员 = 新值  

3.结构体的修饰符 

结构体实例化的修饰符是用于修饰它所存储的位置用memory/storage或者方位权限public````等

如果在函数外实例化,默认强制存储storage不需要写修饰符

如果在函数内实例化,就必须写所存储的位置 

当结构体中存在mapping时,不允许再用memory创建和初始化,要用storage(因为maaping只能存储在storage中)

结构体中的mapping类型,可初始化,也可不初始化,其他类型不可

要对结构体中的mapping操作,只能通过storage的存储来操作 

//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract test {
    struct Student {
        string name;
        int age;
    }
    
    Student public stu;
     
    function set() public returns(string memory,int){
      stu = Student(unicode'大哥',2);
      stu.age=100;
      return (stu.name,stu.age);//大哥,100
    }
    
}

二、Solidity的映射

映射 mapping 是智能合约中很常用的一种数据类型,它是引用类型。

Solidity 映射 mapping 用于以键值对的形式存储数据

键 = key   值 = value  

一个key对应者一个value

它与使用结构体不同,和数组类似,创建后不需要实例化,直接使用

  • 在mapping中key可以是整型、字符串等基本数据类型,但不是引用数据类型和枚举
  • 而value的类型没有数据类型限制,可以是任意数据类型,甚至使用一个mapping作为value也是允许的,

温馨提示:mapping不能作为参数使用,也不能返回整个mapping,只能返回key对应的value

关键字: mapping

映射的定义格式:

mapping(key数据类型 => value数据类型) 权限修饰符 映射名

注意

  • 映射的数据位置只能是 storage,通常用于状态变量。所以它不可以定义存储修饰符
  • 映射可以标记权限修饰符,当权限修饰符为 public, Solidity 会创建一个 getter 函数。 key数据 将成为 getter 的必须参数,并且 getter 会返回 key数据对应的value

映射是没有长度的,也没有 key 的集合或 value 的集合的概念。映射只能是存储的数据位置,因此只允许作为状态变量或作为函数内的存储引用 或 作为库函数的参数。 它们不能用于合约公有函数的参数或返回值。

1.映射的基本使用

查询和修改某个value值

在映射中我们只能查询到value的值,查询不到key的值,也就是说可以通过key查询value但不能通过value查询key

查询value格式:

映射名[key值]

修改value格式:

映射名[key值] = 新value值

初始化映射(删除)

delete 映射名[key值]

注意事项:在映射的查询中,如果赋予一个不存在(没有存储)的key值,那么它所对应和返回的value值就是value数据类型的默认值

//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract test {
    mapping(int=>int) public a;

    function set() public returns(int){
        a[1]=2;
        return a[1];
    }

    function tests(int _b) public view returns(int){
        return a[_b];
    }
    
}

三、Solidity的枚举 

solidity 的枚举类型 是一种用户自定义类型,用于表示多种状态。

枚举类型内部就是一个自定义的整型,默认的类型为uint8,当枚举数足够多时,它会自动变成uint16。(也就是枚举里面存放的元素个数)

枚举类型可以与整数进行显式转换,但不能进行隐式转换。显示转换会在运行时检查数值范围,如果不匹配,将会引起异常。

关键字:enum 

 

定义格式:

enum 枚举名 {     枚举元素1,枚举元素2,枚举元素3,·····    }

注意,枚举的结尾}不需要加;

定义枚举类型变量:

枚举名 权限修饰符 枚举变量名 

枚举类型的变量用于存放枚举里面的某个元素值,默认的值为第一个枚举元素值

给枚举变量赋值:

第一种:枚举内元素赋值

枚举变量名 = 枚举名.枚举元素

第二种:自定义uint类型数据赋值

枚举变量名 = uint类型数据

注意:所给枚举变量赋值的uint类型数据必须是枚举元素内含有的值(枚举元素1-枚举元素n的uint值范围)不是该范围则运行报错

重置枚举变量:将其重置为枚举元素1的值

关键字:delete

格式:

delete 枚举变量名

枚举体语法格式注释:
1)enum必须要有成员对象, { }中不能为空;
2)enum 中不能出现中文;
3){ }中不能加分号

使用枚举类型的主要好处:

  • 明确值的范围,防止错误的值输入。

  • 提高代码的可读性,使得代码更加清晰易懂。

  • 便于维护,需要增加/删除枚举类型的值的时候,只需要修改枚举类型的定义,不需要修改使用枚举类型的代码。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract EnumExample {
    enum Status {
        Pending,
        Shipped,
        Accepted,
        Rejected,
        Canceled
        //枚举类型是unit8数据结构,内部元素均为uint8由0开始按顺序赋值
        //若元素超出了uint8赋值则增加为uint16

        // 枚举元素   对应的uint
        // Pending  --- 0
        // Shipped  --- 1
        // Accepted --- 2
        // Rejected --- 3
        // Canceled --- 4
    }

    //定义了枚举类型的变量
    Status public status; 

    function get() public view returns (Status) {
        return status;  //默认分配Pending 0
    }

    function set1() public {
        status = Status.Canceled; //设置枚举元素Canceled 4
    }

    function set(Status _a) public {
        status = _a; //外部uint值类型  范围  0-4  ,不是该范围则运行报错
    }

    function reset() public {
        delete status;
    }
}

四、数组、结构体、映射的直接相互嵌套

1.没有数组嵌套数组

数组不能嵌套数组,只能数组和数组之间相互赋值

2.数组嵌套结构体

在数组里面存放结构体,我们称之为数组结构体

定义格式:

结构体名[长度] 修饰符 数组名    

提示:长度可写可不写,写了代表定长数组,不写代表变长数组,变长数组要注意一开始没有长度,需要push()添加值(变长)

查询一个下标对应整个结构体格式:

数组名[下标]  

查询一个下标对应结构体的成员值格式:

数组名[下标].结构体成员名

赋值就在查询后面加个 =

作为函数参数的注意事项

当返回的是一个数组结构体值,那么返回的参数也必须是数组结构体

当数组结构体作为形参,那么传入的实参也必须是数组结构体

3.没有数组嵌套映射

数组不能嵌套映射,只能数组和映射相互赋值

4.结构体嵌套数组

在结构体里面让数组作为结构体成员,我们称之为结构体数组
 

结构体数组可以是变长的也可以是定长的

结构体数组定义格式:

struct 结构体名 {

        数据类型[长度] 权限修饰符 数组名;

}

无法给结构体数组初始化赋值

 

访问结构体数组:

实例化结构体名.数组名

访问结构体数组的数组元素

实例化结构体名.数组名[下标]

给某个实例化结构体中的映射赋值

实例化结构体名.数组名[下标] = 元素值

如果是变长数组则是push()赋值

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Example {

    struct  aaa {
        string name;
        int age;
        int[2] arr;
        int[] arr2;
    }

    aaa public a;

    function set() public {
       a.name=unicode'a';
       a.age=19;
       a.arr[0]=123;
       a.arr2.push(10);
    }

    function get() public view returns(int,int){
        return(a.arr[0],a.arr2[0]);
    }

    function getArr() public view returns(int[2] memory){
        return a.arr;
    }

}   

5.结构体嵌套结构体

结构体嵌套结构体,我们称之为结构体结构体,嵌套的里面的结构体是实例化的结构体

结构体结构体定义格式:

struct 结构体名1 {

        成员;

        ·····

}

struct 结构体名 {

        实例化结构体1

}

访问结构体结构体:

实例化结构体名.实例化结构体1

访问结构体数组的数组元素

实例化结构体名.实例化结构体1.实例化结构体1的成员

赋值就后面加 = 

6.结构体嵌套映射

在结构体里面嵌套映射作为结构体的成员,我们成之为结构体映射

注意事项:

  • 当结构体中存在mapping时,不允许再用memory对结构体实例化,要用storage(因为maaping只能存储在storage中)
  • 要对结构体中的mapping操作,只能通过storage的存储来操作
  • 在结构体里面的映射不能加权限修饰符,它强制和struct一样的权限

 

结构体映射定义格式:

struct 结构体名 {

        mapping(key类型 => value类型) 映射名;

}

对结构体实例化并初始化mapping

以大括号引出,不按顺序赋值结构体名  别名= 结构体名(  { key名:值,value名:值  }  )

实例化结构体后对mapping初始化

以大括号引出,按顺序赋值结构体名:  实例化= 结构体名(    { key值,value值    }   )

访问结构体种的映射value值

实例化结构体名.映射名[kye值]

给某个实例化结构体中的映射赋值

实例化结构体名.映射名[key值] = value值

作为函数参数的注意事项

当返回的是一个数组结构映射,那么返回的参数也必须是结构体映射

当结构体映射作为形参,那么传入的实参也必须是结构体

7.映射嵌套数组

映射内的value作为数组,整个数组被映射嵌套,我们称之为映射数组

定义格式:

mapping(key类型 => 数组类型[长度]) 权限修饰符 映射名

访问映射里面存储数组

映射名[key值]         

访问映射里面存储的数组具体值

映射名[key值][下标]   

赋值就在查询后面加个 =

注意事项:映射本身固定为storage类型,因此使用的数组也必须是storage类型

如果里面是动态数组,则需要使用push()来赋值,格式:

映射名[key值].push(值)

8.映射嵌套结构体

映射内的value作为结构体,整个结构体被映射嵌套,我们称之为映射结构体

定义格式:

mapping(key类型 => 结构体名) 权限修饰符 映射名

访问映射里面存储的某个实例化结构体

映射名[key值]         

访问映射里面存储的某个实例化结构体成员

映射名[key值].结构体成员        

赋值就在查询后面加个 =

注意事项:映射本身固定为storage类型,因此使用的结构体也必须是storage类型

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Example {

    struct aaa {
        string name;
        int age;
    }

    mapping(int=>aaa) public bbb;
     
    aaa public a;

    function get(string memory _name,int _age,int _id) public returns(aaa memory,int) {
       a.name=_name;
       a.age=_age;
       bbb[_id]=a;
       return (bbb[_id],bbb[_id].age);
    }

}   

9.映射嵌套映射

映射内的value作为映射,整个内部映射被外部映射嵌套,我们称之为映射映射

定义格式:

mapping(key类型 => mapping(key类型=>value类型)) 权限修饰符 映射名l

例如

mapping(int=>mapping(int=>string)) public a;

访问映射里面存储的映射

映射名[外部key值]    

访问映射里面存储的映射的value值

映射名[外部key值][内部key值]       

赋值就在查询后面加个 =

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SolidityTest {
    mapping(int=>mapping(int=>string)) public a;
    function tran() public returns(string memory) { 
        a[1][2]='a';
        a[1];
        return a[1][2];
    }
}

10、重要说明(间接嵌套)

虽然有些不能直接嵌套,但是可以通过结构体作为媒介进行间接嵌套

而结构体可以通过数组和映射作为媒介间接嵌套

当然有些能直接前嵌套也能间接嵌套

例如

数组-->结构体-->数组

映射-->结构体-->映射

映射--结构体-->数组

数组--结构体-->映射

结构体 -->数组 -->结构体

结构体 -->映射 --> 结构体

五、关于枚举的嵌套

枚举通常都是作为枚举变量使用

枚举只能以枚举变量的形式嵌套在结构体内

使用枚举变量的注意事项:

1.枚举变量的赋值只能给枚举类型变量赋值,或枚举元素

2.枚举变量不能存放到数组、结构体、映射、普通变量中去,因为数据类型不一样

3.枚举变量可以定义到结构体里面,然后对结构体内的枚举变量赋予枚举变量(间接性)

//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
contract Enum{
    enum Status {
        None,
        Padding,
        Shipped,
        Completed,
        Rejected,
        Canceled
    }

    Status public status;//枚举变量

    struct Order {
        address buyer;
        Status status;//结构体嵌套枚举
    }

    Order[] public orders;//数组结构体

    function get() view external returns (Status) {
        return status;//返回枚举变量
    }

    function set(Status _status) external  {
        status = _status;//枚举变量的赋值
    }

    function ship() external {
        status = Status.Shipped;//枚举变量的赋值
    }

    function reset() external{
        delete status;//重置枚举变量
    }
}
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值