基础知识目录
- Solidity数据类型
- Solidity运算符
- Solidity控制结构
- Solidity函数
- Solidity事件
- Solidity修饰器
类型和值
- 所有的数据类型都有默认值,如果没有赋值,就是默认值。也有一定的数值范围。
- 它们通常还包含增、删、改、查4个操作中的其中一个或者几个。(set/get, push/pop, delete)
- 数据类型也包含基础类型和复合类型两种。
- 基础类型:整数,浮点数,布尔值,地址,字节。
- 复合类型:数组,枚举,结构体,映射。
1 | // SPDX-License-Identifier: MIT |
点我查看图片:solidity数据类型大小范围
类型 | 默认值 | 最小值 | 最大值 |
---|---|---|---|
int(默认: int256) | 0 | -2**255 | 2**255-1 |
int128 | 0 | -2**127 | 2**127-1 |
int64 | 0 | -2**63 | 2**63-1 |
int32 | 0 | -2**31 | 2**31-1 |
int16 | 0 | -2**15 | 2**15-1 |
int8 | 0 | -2**7 | 2**7-1 |
uint(默认: uint256) | 0 | 0 | 2**256-1 |
uint128 | 0 | 0 | 2**128-1 |
uint64 | 0 | 0 | 2**64-1 |
uint32 | 0 | 0 | 2**32-1 |
uint16 | 0 | 0 | 2**16-1 |
uint8 | 0 | 0 | 2**8-1 |
- 字节,布尔值
类型 | 默认值 |
---|---|
address | 0x0…(total 40 zeros) |
|bool | false |
数组 - array(增、删、改、查)
- Copilot生成:
- 在memory中不能定义动态数组,不能使用push()和pop()方法
- 动态数组只能存在于状态变量中,stableVariable
- 固定数组可以存在于memory中,也可以存在于状态变量中
- 固定数组的长度是固定的,不能改变;动态数组的长度是动态的,可以改变
- 固定数组的长度是在编译时确定的,动态数组的长度是在运行时确定的
- 固定数组的长度是在定义数组的时候确定的,动态数组的长度是在定义数组的时候确定的,也可以在运行时确定
枚举 - enum(改、查)
- 枚举:是对一个对象的所有可能取到的值的集合。
- set的时候,传入的参数是数字0,1,2…,如果不在枚举定义的范围内,会报错。
- delete会重置默认值,默认值是枚举定义中的第一个值0。
结构体 - struct (增、删、改、查)
- 结构体:是对一个对象的所有属性的集合。
- push()方法
映射 - mapping (增、删、改、查)
- delete map[key],不会删除value,而是把value重置为默认值了
函数返回值 - returns
- Copilot生成:
- 函数返回值可以有多个,也可以没有返回值
- 函数返回值可以是任何类型,包括自定义的类型
- 函数返回值可以是内部函数,也可以是外部函数
- 函数返回值可以是可见的,也可以是不可见的
- 函数返回值可以是常量,也可以是变量
- 函数返回值可以是单个值,也可以是数组,映射,结构体等复合类型
pure view 关键字
view > pure
ChatGPT生成:
在 Solidity 中,
pure
和view
关键字用于标识函数的状态修改行为,以便在编译时进行优化和验证。它们之间的主要区别在于函数对合约状态的访问和修改:pure
函数:
pure
函数声明表示函数不访问合约的状态变量,也不修改状态。它是一个纯函数,仅通过输入参数来计算并返回结果。pure
函数不会访问合约的存储区域,也不会调用其他合约或发送以太币。- 使用
pure
关键字声明的函数对于调用者和其他合约的状态都是完全透明的,可以保证函数的执行结果不受外部环境的影响。
view
函数:
view
函数声明表示函数只读取合约的状态变量,而不修改状态。它也是一个纯函数,因为它不会改变合约的状态。view
函数可以访问合约的存储区域,但不能对其进行修改。它也不能调用其他修改状态的函数。- 使用
view
关键字声明的函数可以在不消耗 gas 的情况下被调用,因为它们不会改变区块链的状态。
总的来说,
pure
和view
关键字都用于标识函数的纯度和对状态的访问和修改行为,但pure
函数不允许访问状态变量,而view
函数允许读取状态变量但不允许修改。
异常报错 - error
- gas费用:require > assert > error
- asser():断言,不能带说明信息,如果断言失败,会消耗所有的gas,所有的状态变量都会被重置,所以不要使用断言。一般不会用,通常在调试的时候使用。
修饰器 - modifier
- 类似于java中的注解,可以在函数前面加修饰器,修饰器可以用来检查函数的输入,比如检查函数的调用者是否是合约的拥有者,是否是合约的管理员,是否是合约的成员等等。
1 | // SPDX-License-Identifier: MIT |
payable关键字
- ChatGPT生成: 在 Solidity 中,
payable
是一个关键字,用于标记函数或变量可以接收以太币。它通常用于两个地方:
函数修饰符: 使用
payable
修饰符标记的函数可以接收以太币。这些函数可以被其他账户发送以太币调用,并且可以执行向其他账户发送以太币的操作。合约构造函数: 在合约构造函数中,如果你想要合约在部署时接收以太币,你可以将构造函数标记为
payable
。
- 以下是使用
payable
的两个示例:
- 函数修饰符:
1
2
3
4
5
6
7
8pragma solidity ^0.8.0;
contract MyContract {
// 接收以太币的函数,标记为 payable
function receiveEther() public payable {
// 函数逻辑
}
}
- 在这个示例中,
receiveEther
函数被标记为payable
,表示它可以接收以太币。调用这个函数时,可以通过msg.value
获取发送的以太币数量。
- 构造函数:
1
2
3
4
5
6
7
8pragma solidity ^0.8.0;
contract MyContract {
// 合约构造函数,标记为 payable
constructor() payable {
// 构造函数逻辑
}
}
- 在这个示例中,合约的构造函数被标记为
payable
,这意味着在部署合约时可以发送以太币。在构造函数中,可以通过msg.value
获取发送的以太币数量。
payable 中transfer(), send(), call()的区别
- ChatGPT生成: 在 Solidity 中,
payable
关键字用于标记合约函数,以表示该函数可以接收以太币。当一个合约需要处理以太币时,通常会使用transfer
、send
或call
函数之一来执行支付操作。这些函数之间有一些区别,下面是它们的简要比较:
transfer
:transfer
是 Solidity 中最简单的发送以太币的方法。- 它是
address
类型的成员函数,只能发送固定的 2300 gas,并且在失败时会抛出异常(即抛出异常后所有状态改变都会被回滚)。 - 它被认为是比较安全的发送以太币的方式,因为它不允许发生回调(也就是说,接收方不能执行代码以影响交易的结果)。
send
:send
函数与transfer
函数相似,但它返回一个布尔值来指示发送是否成功,而不是抛出异常。send
函数会发送所有可用的 gas(最多 2300 gas),但是在发送失败时不会抛出异常,而是返回false
。- 这个函数通常用于与外部地址进行简单的支付操作,但不建议在需要确保交易原子性的情况下使用。
call
:call
函数是最通用的发送以太币的方法,它允许发送任意数量的 gas,并且返回一个布尔值来指示调用是否成功。call
函数可以传递额外的数据和设置 gas 限制,也可以捕获执行过程中的异常。- 这个函数通常用于与合约进行交互,或者需要更复杂逻辑的支付操作。
- 总的来说,
transfer
是最简单且最安全的发送以太币的方法,适用于大多数情况。send
函数在需要检查支付是否成功时比较有用,但在复杂场景下不够灵活。call
函数是最通用的方法,可以满足各种需求,但需要更小心地处理异常情况和 gas 的使用。
public internal external private关键字
修饰变量:internal public private
- 权限开放程度:public > internal > private
- public:公开的,自动生成getter()函数,可以在合约内部外部访问。
- private: 私有的,只能在当前合约中访问,不会生成getter()函数,也不能被子合约继承。
- internal:只能在当前合约或子合约中访问
适用情况 ChatGPT生成:
internal
关键字通常用于需要在当前合约及其派生合约中共享和访问的状态变量。它提供了一种在合约内部实现继承和代码重用的方式,并且可以限制对变量的访问权限,以提高合约的安全性和封装性。- 以下是一些常见的情况下使用
internal
修饰变量的示例:
共享状态数据: 如果你希望在当前合约及其派生合约中共享和访问某个状态变量的值,但不希望它被合约外部的调用者直接访问,你可以将该状态变量声明为
internal
。内部状态追踪: 在复杂的合约中,可能会有一些状态需要在多个函数之间共享和更新。使用
internal
修饰的状态变量可以确保这些状态只能在合约内部被访问和修改,从而降低了出错的可能性。继承和重用: 在使用继承的合约结构中,
internal
修饰的状态变量可以在父合约和子合约之间共享,从而实现代码的重用和扩展。子合约可以直接访问父合约中的internal
变量,而不需要重新定义相同的变量。
- 总的来说,使用
internal
修饰变量可以在合约内部提供数据共享和封装的能力,同时限制对变量的访问权限,使得合约更加安全和可靠。
- 以下是一些常见的情况下使用
修饰函数: internal external public private
权限开放程度:public > internal > external > private
public:公开的,可以在合约内部外部访问。
private: 私有的,只能在当前合约中访问,不能被子合约继承。
internal:只能在当前合约或子合约中访问.
external:外部函数,只能在外部调用,不能在合约内部调用。
ChatGPT生成: 在 Solidity 中,
internal
和external
是用于修饰函数的访问权限的关键字,它们在修饰函数时有以下区别:Internal(内部):
- 使用
internal
关键字修饰的函数只能在当前合约及其派生合约内部调用,无法被合约外部的调用者访问。这种访问权限对于实现合约内部逻辑提供了保护和封装。 - 示例:
1
2
3
4
5
6contract MyContract {
// 内部函数
function internalFunction() internal {
// 函数逻辑
}
}
- 使用
External(外部):
- 使用
external
关键字修饰的函数只能通过外部调用方式来访问,不能在合约内部被直接调用。这种访问权限通常用于合约的接口函数,供合约外部的调用者调用。 - 示例:
1
2
3
4
5
6contract MyContract {
// 外部函数
function externalFunction() external {
// 函数逻辑
}
}
- 使用
- 总的来说,
internal
修饰的函数适用于合约内部调用和继承,而external
修饰的函数适用于合约外部调用。这两种修饰符的选择取决于你希望函数被调用的方式以及对函数的访问权限的要求。
msg 关键字
- ChatGPT生成: 在 Solidity 中,
msg
是一个全局预定义变量,用于提供有关当前交易或消息的信息。它是一个包含以下属性的特殊对象:
msg.sender
:返回当前交易或消息的发送者(即合约调用者的地址)。msg.value
:返回当前交易发送的以太币数量(以 wei 为单位)。msg.data
:返回当前消息的数据。msg.gas
:返回当前交易还剩余的 gas 数量。
这些属性可以在合约的函数中使用,以便根据当前交易或消息的上下文进行逻辑判断或处理。
以下是一个简单的示例,演示了如何在 Solidity 中使用
msg
:
1 | pragma solidity ^0.8.0; |
- 在这个示例中,我们使用了
msg.sender
和msg.value
属性: - 在构造函数中,
owner
变量被设置为部署合约的账户地址,即msg.sender
。 - 在
receive
函数中,接收到的以太币数量被记录在valueReceived
变量中,并且该函数被标记为external
和payable
,表示它可以接收以太币。 - 在
withdraw
函数中,我们检查调用者是否是合约的拥有者(即msg.sender == owner
),然后将合约中的所有以太币发送给拥有者地址。
address(this)
- ChatGPT生成: 在 Solidity 中,
address(this)
是一个特殊的表达式,用于获取当前合约的地址。它通常用于以下场景:
合约内部调用: 当合约需要获取自身的地址时,可以使用
address(this)
表达式来获取。例如,合约可以在部署时记录自己的地址,或者在与其他合约进行交互时将自己的地址传递给它们。支付操作: 当合约需要将自己的地址作为收款地址进行支付操作时,可以使用
address(this)
表达式来获取。例如,在向其他地址发送以太币或者接收以太币时,合约可以使用address(this)
表达式作为收款地址。
- 以下是一些示例,演示了
address(this)
的用法:
1 | pragma solidity ^0.8.0; |
- 在这个示例中,合约在构造函数中使用
address(this)
表达式来获取自身的地址,并将其记录在contractAddress
变量中。在sendEther
函数中,合约可以使用address(this)
表达式作为收款地址来接收以太币。
- 本文标题:solidity基础知识
- 创建时间:2023-08-16 10:32:30
- 本文链接:2023/08/16/Web3/solidity/01-solidity基础知识/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!