前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Solidity 智能合约开发 - 基础:基础语法 基础数据类型、以及用法和示例

Solidity 智能合约开发 - 基础:基础语法 基础数据类型、以及用法和示例

作者头像
苏泽
发布2024-03-16 10:56:25
1310
发布2024-03-16 10:56:25
举报
数据类型
  1. 基本数据类型:
    • 整型(uint、int):用于表示整数,可以指定位数,如 uint256。 示例:uint256 myNumber = 10;
    • 布尔型(bool):用于表示真(true)或假(false)。 示例:bool isTrue = true;
  2. 地址类型(address):
    • 用于存储以太坊地址,可以是外部账户或智能合约地址。 示例:address myAddress = 0xAbcdef1234567890;
  3. 字符串类型(string):
    • 用于存储文本字符串。 示例:string myString = "Hello, World!";
  4. 数组类型(array):
    • 用于存储相同类型的元素集合。 示例:uint256[] myArray = [1, 2, 3];
  5. 结构体类型(struct):

用于自定义复合类型,可以包含多个字段。 示例:

代码语言:javascript
复制
Copy Code
struct Person {
    string name;
    uint age;
}
Person myPerson;
myPerson.name = "Alice";
myPerson.age = 25;
  1. Enum

Enum 是枚举类型,可以通过以下语法来定义

代码语言:javascript
复制
enum Status {
    Unknown,
    Start,
    End,
    Pause
}
并通过以下语法来进行更新与初始化


// 实例化枚举类型
Status public status;

// 更新枚举值
function pause() public {
    status = Status.Pause;
}

// 初始化枚举值
function reset() public {
    delete status;
}
  1. 映射类型(mapping):
    1. 用于存储键值对数据结构。 示例:
代码语言:javascript
复制
Copy Code
mapping(address => uint256) balances;
balances[msg.sender] = 100;

关键字

  1. "view" 关键字

用于标识一个函数不会修改合约的状态,即它只能读取数据而不能修改数据。这意味着在调用视图函数时,不会产生任何交易费用,并且不会改变合约的状态。例如:

代码语言:javascript
复制

function getName() public view returns (string memory) {return name; }

  1. "pure" 关键字

用于标识一个函数既不会修改合约的状态,也不会读取或访问合约的存储数据。这种函数通常用于执行纯粹的计算操作,不涉及存储或外部调用。例如:

代码语言:javascript
复制

function add(uint256 a, uint256 b) public pure returns (uint256) {return ab; }

  1. "public":
  2. 将函数或变量声明为公共的,可以被合约内部和外部访问。例如:

string public name = "Alice";

  1. "private":
  2. 将函数或变量声明为私有的,只能在合约内部访问。例如:

uint256 private balance = 100;

  1. "external":

将函数声明为外部函数,只能从合约外部调用。与 "public" 关键字不同的是,外部函数不能在合约内部直接调用,也不能被合约继承。例如:

Copy Code function transfer(address recipient, uint256 amount) external { // transfer logic here }

  1. "internal":

将函数声明为内部函数,只能在合约内部或合约继承链上的合约中访问。例如:

function withdraw(uint256 amount) internal { // withdraw logic here }

  1. "payable":

将函数声明为可以接收以太、币的函数,在函数中可以接收以太币并进行转账操作。例如:

function purchase() public payable {// purchase logic here }

函数

  1. 函数定义和调用:
    • 定义函数并在需要时进行调用。 示例:
代码语言:javascript
复制
Copy Code
function sayHello(string memory name) public {// 函数逻辑// ...
}
sayHello("Alice");
  1. 函数可见性(public、private等):
    • 可以限制函数的访问权限。 示例:
代码语言:javascript
复制
Copy Code
function myFunction() public {// 可公开访问的函数
}
function privateFunction() private {// 私有函数,只能在合约内部调用
}

函数修饰器(modifier):

用于修改函数的行为。 示例:

代码语言:javascript
复制
Copy Code
modifier onlyOwner() {
    require(msg.sender == owner, "Only owner can call this function.");_;
}
function changeName(string memory newName) public onlyOwner {// 只有合约所有者可以调用该函数
    name = newName;
}

函数返回值:

  • 可以定义函数的返回类型,并在函数结束时返回相应的值。 示例:
代码语言:javascript
复制
Copy Code
function add(uint256 a, uint256 b) public pure returns (uint256) {return a + b;
}
uint256 result = add(2, 3);  // result = 5

数组

  1. 数组定义和初始化:
    • 定义数组并指定元素个数或直接初始化数组。 示例:
代码语言:javascript
复制
uint256[] myArray;  // 空数组uint256[] myArray2 = new uint256[](3);  // 长度为3的动态数组uint256[] myArray3 = [1, 2, 3];  // 直接初始化数组
  1. 数组长度和访问元素:
    • 可以使用 length 属性获取数组长度,并通过索引访问数组元素。 示例:
代码语言:javascript
复制
 uint256[] myArray = [1, 2, 3]; uint256 length = myArray.length; // length = 3uint256 secondElement = myArray[1]; // secondElement = 2
  1. 动态数组和静态数组:
    • 动态数组的长度可以在运行时更改,而静态数组的长度在编译时确定。 示例:
代码语言:javascript
复制
uint256[] dynamicArray;
uint256[3] staticArray;
  1. 多维数组:
    • 数组可以有多个维度,可以是二维、三维等。 示例:
代码语言:javascript
复制
uint256[][] twoDimensionalArray;
uint256[2][3] twoByThreeArray;

结构体

  1. 结构体定义和初始化:
    • 定义结构体类型并初始化结构体变量。 示例:
代码语言:javascript
复制
struct Person {
    string name;
    uint age;
}
Person myPerson;
myPerson.name = "Alice";
myPerson.age = 25;
  1. 结构体成员访问:
    • 可以通过结构体变量名和成员名访问结构体成员。 示例:
代码语言:javascript
复制
Person myPerson;
myPerson.name = "Alice";
string memory personName = myPerson.name;  // personName = "Alice"
  1. 结构体作为函数参数和返回值:
    • 可以将结构体作为函数的参数或返回值进行传递。 示例:
代码语言:javascript
复制
struct Person {
    string name;
    uint age;
}
function getPerson() public view returns (Person memory) {
    Person memory person;
    person.name = "Alice";
    person.age = 25;
    return person;
}
Person memory myPerson = getPerson();

结构体数组:

结构体可以组成数组,并通过索引访问数组元素。 示例:

代码语言:javascript
复制
struct Person {
    string name;
    uint age;
}
Person[] people;
Person memory person1;
person1.name = "Alice";
person1.age = 25;
people.push(person1);
Person memory person2;
person2.name = "Bob";
person2.age = 30;
people.push(person2);

储存方式

当在Solidity中声明变量时,可以使用不同的存储位置修饰符来指定变量应该存储在何处。共有三种存储位置:memorystoragecalldata。其中,memorystorage是最常用的两种。

  1. memory
    • memory 是一种临时存储位置,用于存储函数执行期间的临时数据。它适用于需要在函数内部进行临时计算或处理大量数据的情况。在函数执行完毕后,memory 中的数据会被清空。
    • 可以使用 memory 关键字将变量声明为 memory 类型,也可以在函数参数中使用 memory。 示例:
代码语言:javascript
复制
function processArray(uint256 memory myArray) public {// 在 memory 中处理数组// ... }
  1. storage
    • storage 是一种永久性存储位置,用于在合约的存储空间中存储和访问数据。它适用于需要在不同函数之间共享和保留数据的情况。在合约中声明的 state variables 默认是 storage 类型。
    • 可以直接在函数内部使用 storage 类型的变量,无需显式声明。 示例:
  2. calldata
    • calldata 是一种特殊的存储位置,用于存储函数参数和外部函数调用的输入数据。calldata 中的数据是只读的,不能被修改。此存储位置适用于函数参数传递和与外部合约交互。
    • 在函数参数中,默认情况下,所有的非 mapping 类型参数都被视为 calldata 类型。 示例:
代码语言:javascript
复制
function processInputData(uint256 calldata inputData) external {// 处理输入数据
}

function callExternalContract(address externalContract, bytes calldata data) external {
    (bool success, ) = externalContract.call(data);
    require(success, "External contract call failed.");
}

总结一下:

  • memory 用于临时存储函数执行期间的数据,适用于临时计算或处理大量数据的情况;
  • storage 用于永久性存储变量,适用于在不同函数之间共享和保留数据的情况;
  • calldata 用于存储函数参数和外部函数调用的输入数据,是只读的。

堆栈(Stack):

Solidity 中的堆栈主要用于函数调用的内部状态维护。每当一个函数被调用时,它会在堆栈上创建一个新的帧,该帧包含了这个函数的参数、局部变量、返回地址等信息。当函数执行完毕后,该帧将从堆栈中弹出。

通常情况下,开发者不需要手动操作堆栈,Solidity 编译器会自动进行堆栈管理。但在一些需要优化调用栈空间的场景下,可能需要手动控制函数调用堆栈的大小和顺序。 示例:

代码语言:javascript
复制
function foo(uint256 x, uint256 y) public pure returns (uint256) {
    uint256 result = bar(x) + y;return result;
}

function bar(uint256 x) public pure returns (uint256) {
    uint256 result = x * 2;return result;
}
  1. 日志(Logs):
    • Solidity 中的日志主要用于记录合约内部的事件,如状态变更、交易处理等。通过日志,可以在区块链上查看合约的历史状态变化,并进行事件通知和监听。
    • 日志由合约的事件(event)和事件参数组成,可以通过 emit 关键字触发。日志数据会被写入到交易的日志中,不会影响合约状态,但会占用一定的 Gas。 示例:
代码语言:javascript
复制
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address _to, uint256 _value) public {
    require(balances[msg.sender] >= _value, "Insufficient balance.");
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    emit Transfer(msg.sender, _to, _value);
}
  1. Code

Solidity 中的一种特殊的数据类型,用于存储合约的字节码。

在 Solidity 中,合约代码(也称为字节码)可以通过 type 关键字将其存储在 bytesbytescode 类型的变量中。这样可以在合约内部或外部对代码进行处理和分析。

以下是一个简单的示例,展示了如何将合约代码存储在 bytes 类型的变量中:

代码语言:javascript
复制
pragma solidity ^0.8.0;

contract CodeExample {
    bytes public contractCode;
    constructor() {
        // 将合约代码存储在 contractCode 变量中
        contractCode = type(CodeExample).creationCode;
    }
}

Mappings

  1. 映射定义和初始化:
    • 定义映射类型,并通过键值对存储和访问数据。 示例:

mapping(address => uint256) balances;

  1. 映射的键值对:
    • 映射由键值对组成,通过键来访问对应的值。 示例:
代码语言:javascript
复制
mapping(address => uint256) balances; 
address account = 0xAbcdef1234567890; balances[account] = 100;
  1. 映射的访问和修改:
    • 可以通过键来访问或修改映射中的值。 示例:
代码语言:javascript
复制
mapping(address => uint256) balances;
 address account = 0xAbcdef1234567890; uint256 balance = balances[account]; // 获取映射值 balances[account] = 200; // 修改映射值
  1. 映射的迭代:
  • Solidity 中的映射不支持直接迭代,需要结合其他数据结构或编写逻辑来实现迭代功能。

在 Solidity 中,映射(Mapping)是一种键值对的数据结构,类似于字典或哈希表。每个键对应一个唯一的值。但是,Solidity 中的映射并不支持直接迭代,这意味着你无法像遍历数组或列表那样直接对映射进行循环迭代。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关键字
  • 函数
    • 函数修饰器(modifier):
      • 函数返回值:
      • 数组
      • 结构体
        • 结构体数组:
        • 储存方式
          • 堆栈(Stack):
          • Mappings
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档