目录
1、修饰符(external、public、internal、private)的区别
2、在智能合约中这四个不同的区别代表的含义this msg block tx
2.用法:selfdestruct(_addr)及示例代码:
4、函数 bytes.concat 和 string.concat
1.Solidity支持两种类型的循环:for循环和while循环。
结语:solidity基础知识暂时补充到这里,如有错误可以联系我修正。
1、修饰符(external、public、internal、private)的区别
external(外部):外部函数只能通过合约外部的消息调用执行,不能被内部函数或其他合约调用。
public(公共):公共函数可以被任何地址调用,包括合约内部、合约外部和其他合约。
internal(内部):内部函数只能在当前合约内部调用,无法被合约的外部或其他合约调用。
private(私有):私有函数只能在当前合约内部访问,无法被合约的外部或其他合约调用。
view(视图):视图函数声明不会修改合约的状态,只能读取数据。
pure(纯函数):无法查看无法修改
2、在智能合约中这四个不同的区别代表的含义this msg block tx
this:指这个合约的实例
msg:代表了当前正在处理的消息(交易)。
block:代表了以太坊网络中的一个区块,包含了多个交易的集合。
tx:代表了在以太坊网络中发送的一笔交易,并提供交易信息。
3、self destruct(合约销毁)
1. 什么情况下需要使用合约销毁?
销毁合约只是让你的智能合约无法再继续工作,但是在区块链上的数据还是保留的。什么情况下需要使用到销毁合约?
你的智能合约在不使用的情况下,你可以把它给销毁。
强迫你的用户放弃旧的智能合约,使用新的智能合约,所以必须把旧的给销毁。但是由于目前智能合约是能够升级的,所以不赞成使用这方法。
你的合约受攻击到了不可挽回的地步,就必须被迫强行销毁。记得,在销毁之前你必须把旧合约内的代币给迁移出来,不然你旧合约的代币也是找不回来的。
2.用法:selfdestruct(_addr)及示例代码:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract Selfdestruct{
constructor() payable {}
function deleteSelf(address _addr) external {
selfdestruct(payable(_addr));
}
function getBalance() external view returns(uint) {
return address(this).balance;
}
}
4、events
1.什么是events:
Solidity 事件是EVM的日志功能之上的抽象。日志是不存在区块链上的,通过event可以记录链上发生的事情,并且通过日志的形式显示出来。
事件在合约中可被继承。当他们被调用时,会使参数被存储到交易的日志中 —— 一种区块链中的特殊数据结构。 这些日志与地址相关联,被并入区块链中,只要区块可以访问就一直存在(现在开始会被永久保存,在 Serenity 版本中可能会改动)。 日志和事件在合约内不可直接被访问(甚至是创建日志的合约也不能访问)。
2.示例代码:
contract Event{
event Log(address indexed sender, string message);//indexed可以理解为按照顺序排列的
event AnotherLog(address indexed sender01, string message01 , uint _i);
event EmptyLog();
function test() public {
emit Log(msg.sender ,"Hello World");
emit Log(msg.sender , "Hello Evm");
emit AnotherLog(msg.sender, "test another" , 3);
emit EmptyLog();
}
}
5、arrays(数组)
数组可以在声明时指定长度,也可以动态调整大小(长度)。
一个元素类型为 T,固定长度为 k 的数组可以声明为 T[k],而动态数组声明为 T[]。 举个例子,一个长度为 5,元素类型为 uint 的动态数组的数组(二维数组),应声明为 uint[][5] (注意这里跟其它语言比,数组长度的声明位置是反的)。
1、长度固定的数组
uint[]
定义的数组,可以使用引用查看索引位置的数值,使用.length
得到数组的长度byte
定义的数组,将字符串以十六进制形式保存,不能使用.length
。byte
默认值为0
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract FixedSizeArrays{
uint[3] public numbers = [2, 3, 4];
bytes1 public b1;
bytes2 public b2;
bytes3 public b3;
function setElement(uint index,uint value) public{
numbers[index] = value;
// b3[index] = value;
}
function getLength() public view returns(uint){
return numbers.length;
// return bytes3.length;
}
function setBytesArraty() public{
b1='a';
b2='ab';
b3='z';
}
}
2、动态数组
- 可以使用push 和 pop 函数
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract DynamicArrays{
uint[] public numbers;
function getLength() public view returns(uint){
return numbers.length;
}
function addElement(uint item) public{
numbers.push(item);
}
function getElement(uint i) public view returns(uint){
if(i < numbers.length){
return numbers[i];
}
return 0;
}
}
3、string 和 bytes
bytes 和 string 类型的变量是特殊的数组。 bytes 类似于 bytes1[],但它在 调用数据calldata 和 内存memory 中会被“紧打包”
Solidity没有字符串操作函数,但是可以使用第三方字符串库,我们可以比较两个字符串通过计算他们的 keccak256-hash ,可使用 keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)) 和使用 string.concat(s1, s2) 来拼接字符串。
我们更多时候应该使用 bytes 而不是 bytes1[] ,因为Gas 费用更低, 在 内存memory 中使用 bytes1[] 时,会在元素之间添加31个填充字节。 而在 存储storage 中,由于紧密包装,这没有填充字节, 参考 bytes and string 。 作为一个基本规则,对任意长度的原始字节数据使用 bytes,对任意长度字符串(UTF-8)数据使用 string 。
如果使用一个长度限制的字节数组,应该使用一个 bytes1 到 bytes32 的具体类型,因为它们便宜得多。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract BytesAndString{
bytes public b = 'abc';
string public s;
function getElement() public view returns(bytes1){
return b[0];
// return s[0];
}
function getLength() public view returns(uint){
return b.length;
// return s.length;
}
}
4、函数 bytes.concat 和 string.concat
可以使用 string.concat 连接任意数量的 string 字符串。 该函数返回一个 string memory ,包含所有参数的内容,无填充方式拼接在一起。 如果你想使用不能隐式转换为 string 的其他类型作为参数,你需要先把它们转换为 string。
6、looping(循环)
循环是一种常见的控制结构,用于重复执行一段代码。循环的作用是在满足特定条件的情况下,反复执行一段代码,以达到重复操作的目的。
1.Solidity支持两种类型的循环:for循环和while循环。
For循环:
for循环用于在指定条件下重复执行一段代码。它的语法如下:
for (初始化语句; 条件表达式; 更新语句) {
// 循环体
}
示例代码:
pragma solidity ^0.8.0;
contract LoopExample {
function loopExample() public pure returns(uint) {
uint sum = 0;
for (uint i = 1; i <= 10; i++) {
sum += i;
}
return sum;
}
}
上述示例代码中,for循环从1到10,将每个数字累加到sum变量中,最后返回sum的值。
While循环:
while循环用于在指定条件为真时重复执行一段代码。它的语法如下:
while (条件表达式) {
// 循环体
}
示例代码:
pragma solidity ^0.8.0;
contract LoopExample {
function loopExample() public pure returns(uint) {
uint i = 1;
uint sum = 0;
while (i <= 10) {
sum += i;
i++;
}
return sum;
}
}
上述示例代码中,while循环从1开始,每次将i累加到sum变量中,直到i大于10时停止循环,并返回sum的值。
2.循环结构
在Solidity中的作用是使得我们能够重复执行一段代码,从而实现复杂的逻辑和功能。通过循环,我们可以遍历数组、执行多次计算、处理大量数据等。循环结构的灵活性和重复执行的特性使得我们能够更高效地编写和管理代码。
7、Gas
Gas是以太坊网络中的计算单位,用于衡量执行智能合约所需的计算量。在执行智能合约时,需要支付相应的 Gas 费用。
8、智能合约理论
1.智能合约是一种在区块链上执行的自动化合约。
2.它们是由代码编写的,可以在区块链上执行和验证。
3.智能合约可以存储数据、执行计算和与其他合约进行交互。
1、部署智能合约:
部署智能合约意味着将合约代码上传到区块链网络,并在区块链上创建一个合约实例。
智能合约可以通过多种方式进行部署,包括使用以太坊的 Remix IDE、metamask或 Web3.js 等工具。
在部署智能合约时,需要支付一定数量的 Gas 费用。
部署后,智能合约将在区块链上具有唯一的地址,并可以通过该地址与之交互。
9、常见的数据类型
数据类型包括整数(int)、无符号整数(uint)、布尔值(bool)、地址(address)等。
整数:int8、int16、int32、int64 等,表示有符号整数,范围为 -2^(n-1) 到 2^(n-1)-1,其中 n 是位数。
无符号整数:uint8、uint16、uint32、uint64 等,表示无符号整数,范围为 0 到 2^n-1,其中 n 是位数。
布尔值:bool,表示 true 或 false。
地址:address,用于存储 Ethereum 地址,长度为 20 字节。
10、运算符
solidity 支持常见的算术运算符(+、-、*、/、%)和逻辑运算符(&&、||、!)。
Solidity 还支持位运算符(&、|、^、<<、>>)用于处理位级别操作。
类型转换可通过显式转换来实现,例如将一个整数转换为另一个整数类型或将一个整数转换为地址类型。
11、mapping
mapping一种重要的数据结构,用于存储键值对。
映射的声明形式为 mapping(keyType => valueType) mapName;,其中 keyType 和 valueType 分别表示键和值的数据类型。
可以通过键来访问和修改映射中的值。
映射在智能合约中常用于存储数据、记录状态等