首页 > 其他分享 >智能合约-solidity

智能合约-solidity

时间:2023-09-27 09:45:40浏览次数:41  
标签:function 函数 uint256 solidity 智能 bool address 合约 public

智能合约-solidity语言学习

Solidity是一种静态类型语言,这意味着每个变量(状态变量和局部变量)都需要在编译时指

定变量的类型。

Solidity 提供了几种基本类型,并且基本类型可以用来组合出复杂类型。

除此之外,类型之间可以在包含运算符号的表达式中进行交互。 关于各种运算符号,可以参考 运算符优先级

“undefined”或“null”值的概念在Solidity中不存在,但是新声明的变量总是有一个 默认值 ,具体的默认值跟类型相关。 要处理任何意外的值,应该使用 错误处理 来恢复整个交易,或者返回一个带有第二个 bool 值的元组表示成功。

1.HelloWeb3(三行代码)

注意写合约脚本时,要规范框架:

// SPDX-License-Identifier: MIT  
pragma solidity ^0.8.4;           
contract HelloWeb3{
    string public _string = "Hello Web3!";
}

每行代码的含义:

1:介绍软件许可

2:声明源文件所用的solidity版本,只能编译 [0.8.4 , 0.9.0) 版本

3-4:定义一个合约。第3行创建合约(contract),并声明合约的名字 HelloWeb3。第4行是合约的内容,我们声明了一个string(字符串)变量_string,并给他赋值 “Hello Web3!”。

值类型

Types

以下类型也称为值类型,因为这些类型的变量将始终按值来传递。 也就是说,当这些变量被用作函数参数或者用在赋值语句中时,总会进行值拷贝。

布尔类型

:可能的取值为字面常量值 truefalse

    // 布尔运算
    bool public _bool1 = !_bool; //取非
    bool public _bool2 = _bool && _bool1; //与
    bool public _bool3 = _bool || _bool1; //或
    bool public _bool4 = _bool == _bool1; //相等
    bool public _bool5 = _bool != _bool1; //不相等

整型

uint , int int / uint :分别表示有符号和无符号的不同位数的整型变量。 支持关键字 uint8uint256 (无符号,从 8 位到 256 位)以及 int8int256,以 8 位为步长递增。 uintint 分别是 uint256int256 的别名

对于整形 X,可以使用 type(X).mintype(X).max 去获取这个类型的最小值与最大值

    // 整数运算
    uint256 public _number1 = _number + 1; // +,-,*,/
    uint256 public _number2 = 2**2; // 指数
    uint256 public _number3 = 7 % 2; // 取余数
    bool public _numberbool = _number2 > _number3; // 比大小

地址类型

地址类型有两种形式,他们大致相同:

  • address:保存一个20字节的值(以太坊地址的大小)。
  • address payable :可支付地址,与 address 相同,不过有成员函数 transfersend

这种区别背后的思想是 address payable 可以向其发送以太币,而不能先一个普通的 address 发送以太币,例如,它可能是一个智能合约地址,并且不支持接收以太币。

类型转换:

允许从 address payableaddress 的隐式转换,而从 addressaddress payable 必须显示的转换, 通过 payable(<address>) 进行转换。

address 允许和 uint160、 整型字面常量、bytes20 及合约类型相互转换。

​ 只能通过 payable(...) 表达式把 address 类型和合约类型转换为 address payable。 只有能接 收以太币的合约类型,才能够进行此转换。例如合约要么有 receive 或可支付的回退函数。 注意 payable(0) 是有效的,这是此规则的例外。

  • 地址类型成员变量

    查看所有的成员,可参考 地址成员

    • balancetransfer 成员

    可以使用 balance 属性来查询一个地址的余额, 也可以使用 transfer 函数向一个可支付地址(payable address)发送 以太币Ether (以 wei 为单位):

    address x = 0x123;
    address myAddress = this;
    if (x.balance < 10 && myAddress.balance >= 10) 
               x.transfer(10);
    

    如果当前合约的余额不够多,则 transfer 函数会执行失败,或者如果以太转移被接收帐户拒绝, transfer 函数同样会失败而进行回退

    // 地址定义
    address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
    address payable public _address1 = payable(_address); 
    
    // payable address,可以转账、查余额
    // balance
    uint256 public balance = _address1.balance; 
    // transfer
    address payable addr;
    addr.transfer(1);//合约向addr转账1wei
    
    address x = 0x123;
    address myAddress = this;
    if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);// 向 x 转账 10?

定长字节数组

  • 一个字节占两位,字节乘2是位数(16进制)

  • 字节数组bytes分两种,一种定长(byte, bytes8, bytes32),另一种不定长。不定长的使用频率低,暂时先略过。

  • 定长bytes可以存一些数据,消耗gas比较少。

        // 固定长度的字节数组
        bytes32 public _byte32 = "MiniSolidity"; 
        bytes1 public _byte = _byte32[0]; 
    
  • MiniSolidity 字符串以字节的方式存储进数组_byte32 ,转换成16进制为:

0x4d696e69536f6c69646974790000000000000000000000000000000000000000

  • 0x是象征意义,表示十六进制,四位二进制组成一位十六进制

  • 一个字节占 8 bit,也就是两位十六进制

  • 例如 bytes32 类型有64个16进制位。

  • _byte变量存储_byte32数组的第一个字节,即0x4d (0x是象征意义,代表十六进制)。

// SPDX-License-Identifier: SimPL-2.0
pragma solidity ^0.8.7; 

contract SimpleStorage{

// Solidity是一种静态类型语言,这意味着每个变量(状态变量和局部变量)都需要在编译时指定变量的类型
// 基础数据类型 : bool,uint,int,address,bytes
// 布尔类型
    bool istrue;
// 整型:有符号和无符号
    uint storeData;
    int a;
    int b;
// 地址类型 address,address payable(可支付地址,与address相同,不过有成员transfer和send)
// 可进行相关的类型转换
    address myauont;
    address payable youauont;

// 地址类型可以理解为封装了一些常用方法的类。
// 地址类型成员变量 :详细的可以查看文档

// <address>.balance (uint256) 以 Wei 为单位的地址类型 Address 的余额。
// <address>.codehash (bytes32) 地址类型 Address 的codehash
// <address payable>.transfer(uint256 amount)
// 向 地址类型 Address 发送数量为 amount 的 Wei,失败时抛出异常,使用固定(不可调节)的 2300 gas 的矿工费。
// <address payable>.send(uint256 amount) returns (bool)
// 向 地址类型 Address 发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。

//   可以使用 balance 属性来查询一个地址的余额, 也可以使用 transfer 函数向一个可支付地址(payable address)发送 以太币Ether (以 wei 为单位)
// if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);


    function set(uint x) public {
        storeData = x;
    }
    // view、pure等这些参数是函数的修饰符,view 原名 contant
    // 可以将函数声明为view类型,这种情况下要保证不修改状态。
    //函数可以声明为 pure ,在这种情况下,承诺不读取也不修改状态变量。
    function get() public view returns (uint){
        return storeData;
    }
    function f (uint x) public pure returns (uint) {
        return x + 1;
    }
    // 函数重载
 
    // 还有一些特别的函数:
}

函数

Functions

函数定义

函数 function、函数名、(传入参数)、可见性、gas 节省支付性、returns (传出参数)

函数主体{…}前面的开头内容与属性:

    function   function name(types name)   internal|external|public|private   [pure|view|payable]   [returns (types name)]{
    [return] 
    }

中括号部分可省略不写,顺序依次为:function、函数名、(传入参数)、可见性、gas 节省支付性、returns (传出参数)

1.function
声明函数时的固定用法,想写函数,就要以function关键字开头。

2.function name
函数名。

3.(types name)
圆括号里写输入到函数的现实变量类型和名字。

4.internal|external|public|private
函数可见性说明符,一共4种。没标明函数类型的,默认internal。

  • public: 内部外部均可见。(也可用于修饰状态变量,public变量会自动生成 getter函数,用于查询数值).

  • private: 只能从本合约内部访问,继承的合约也不能用(也可用于修饰状态变量)。

  • external: 只能从合约外部访问(但是可以用this.函数名()来调用

  • internal: 只能从合约内部访问,继承的合约可以用(也可用于修饰状态变量)。

5.pure|view|payable
决定函数权限/功能的关键字。payable(可支付的)很好理解,带着它的函数,运行的时候可以给合约转入ETH。

6.returns (types name)
函数返回的变量类型和名称。

函数修饰符

有决定函数何时和被谁调用的可见性修饰符,

private(只能被合约内部调用);

internal(就像private,但是它也能被继承的合约调用);

external(只能从合约外部调用);

public(可以在任何地方调用,无论内部还是外部)。

还有状态修饰符,告诉我们函数如何和区块链交互,view(我们运行这个函数不会更改和保存任何数据);pure(我们的函数不但不会往区块链写数据,它甚至不从区块链读取数据)。这两种修饰符在被从合约外部调用的时候都不话费任何gas(但是它们在被内部其他函数调用的时候会耗费gas)

internal 与external

    // internal: 内部
    function minus() internal {
        number = number - 1;
    }

    // 合约内的函数可以调用内部函数
    function minusCall() external {
        minus();
    }

pure 与 view [gas 节省支付性]

  1. pure:不能读取也不能写入链上变量

  2. view:只能读取但不能写入链上变量

  3. 不写 pure 或 view:可读可写

solidity在函数中加入这两个关键字,是为了节省智能合约中特有的gas fee。合约的状态变量存储在链上所需要的gas fee很贵,如果不改变链上状态,就不用付gas。包含pure跟view关键字的函数是不改写链上状态的,因此用户直接调用他们是不需要付gas的(合约中非pure/view函数调用它们则会改写链上状态,需要付gas)

 
 contract SimpleStorage {
 uint256  public  favoriteNumber;  
   function retrieve() public view returns (uint256){
        favoriteNumber = favoriteNumber+1; ×
        return favoriteNumber;
    }
   }
    这里就错误了,因为是view修饰的函数,因此这个函数中就不能更改和保存合约里的数据,view 是个纯函数,表示视图,不需要花费gas,因为我们不是修改状态,也就是其按钮是蓝色的原因。只call但不发送交易。
    
      function retrieve() public pure  returns (uint256){
        return favoriteNumber;  ×
        return 7;
    }
    
    这里就错误了,它甚至不从区块链读取数据 ,从存储的地方获取。

在以太坊中,以下语句被视为修改链上状态:

  1. 写入状态变量。
  2. 释放事件。
  3. 创建其他合同。
  4. 使用selfdestruct.
  5. 通过调用发送以太币。
  6. 调用任何未标记viewpure的函数。
  7. 使用低级调用(low-level calls)。
  8. 使用包含某些操作码的内联汇编。

如上图所示,公主代表合约中的状态变量(存储在链上),上层为公主,下层人物从左往右对公主的权限依次提高,分别为纯纯牛马、看客、默认 boss

  • pure,中文意思是“纯”,在solidity里理解为“纯纯牛马”。包含pure关键字的函数,不能读取也不能写入存储在链上的状态变量。就像小怪一样,看不到也摸不到公主。
  • view,“看”,在solidity里理解为“看客”。包含view关键字的函数,能读取但也不能写入状态变量。类似马里奥,能看到碧池,但终究是看客,不能入洞房。
  • 不写pure也不写view,函数既可以读取也可以写入状态变量。类似马里奥里的默认boss,可以对公主为所欲为…

例如我们在合约里定义一个状态变量 number = 5

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    contract FunctionTypes{
        uint256 public number = 5;

定义一个add()函数,每次调用,每次给number + 1

    // 默认
    function add() external{
        number = number + 1;
    }

如果add()包含了pure关键字,例如 function add() pure external,就会报错。因为pure(纯纯牛马)是不配读取合约里的状态变量的,更不配改写。

那pure函数能做些什么?举个例子,你可以给函数传递一个参数 _number,然后让他返回 _number+1。

    // pure: 纯纯牛马
    function addPure(uint256 _number) external pure returns(uint256 new_number){
        new_number = _number+1;
    }

如果add()包含view,比如function add() view external,也会报错。因为view能读取,但不能够改写状态变量。可以稍微改写下方程,让他不改写number,而是返回一个新的变量。

    // view: 看客
    function addView() external view returns(uint256 new_number) {
        new_number = number + 1;
    }

上述+1的函数例子中,pure 需要在函数定义时传入需要的参数, view 则不需要,可以直接读取已有的参数。不过两者都不能改变链上已有的参数。

payable [gas 节省支付性]

    // payable: 递钱,能给合约支付eth的函数
    function minusPayable() external payable returns(uint256 balance) {
        minus(); //-1   
        balance = address(this).balance;
    }

我们定义一个external payableminusPayable()函数,间接的调用minus(),并且返回合约里的ETH余额(this关键字可以让我们引用当前合约的地址)。 我们可以在调用minusPayable()时,往合约里转入1个ETH

我们可以在返回的信息中看到,合约的余额是1 ETH

函数输出

主要还是用命名式返回,直接 returns(参数类型 参数名)

Solidity有两个关键字与函数输出相关:returnreturns

Solidity函数输出主要包括:类型返回、命名式返回、解构式赋值。

返回值 return和returns

他们的区别在于:

  • returns加在函数名后面,用于声明返回的变量类型及变量名;

  • return用于函数主体中,返回指定的变量。

类型返回

    // 类型返回
    function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){
            return(1, true, [uint256(1),2,5]);
        }

上面这段代码中,我们声明了returnMultiple()函数将有多个输出:returns(uint256, bool, uint256[3] memory),接着我们在函数主体中用return(1, true, [uint256(1),2,5])确定了返回值。

命名式返回

我们可以在returns中标明返回变量的名称,这样solidity会自动给这些变量初始化,并且自动返回这些函数的值,不需要加return

// 命名式返回
function returnNamed() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){
    _number = 2;
    _bool = false; 
    _array = [uint256(3),2,1];
}

在上面的代码中,我们用returns(uint256 _number, bool _bool, uint256[3] memory _array)声明了返回变量类型以及变量名。这样,我们在主体中只需要给变量_number,_bool和_array赋值就可以自动返回了。

当然,你也可以在命名式返回中用return来返回变量:

// 命名式返回,依然支持return
function returnNamed2() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){
    return(1, true, [uint256(1),2,5]);
}

解析式赋值

solidity使用解构式赋值的规则,支持读取函数的全部部分返回值。

  • 读取所有返回值:声明变量,并且将要赋值的变量用,隔开,按顺序排列
    uint256 _number;
    bool _bool;
    uint256[3] memory _array;
    (_number, _bool, _array) = returnNamed();
  • 读取部分返回值:声明要读取的返回值对应的变量,不读取的留空。下面这段代码中,我们只读取_bool,而不读取返回的_number_array

     ``` solidity
             (, _bool2, ) = returnNamed();
     ```
    

数组和结构体

Arrays &Structs

数组

 //数组和其他语言中的一样
 uint256[] listOfFavoriteNumbers ; // [77,78,90] 与其他编程语言数组一样
 

结构体

  // 定义结构体,相当于构建自己的类型,类似于类
    struct Person{
        string name;
        uint256 favoriteNumber;

    }
    Person[] person;
    直接赋值
    Person public  pat  = Person("pat",7);
    或者按属性名赋值
    Person public  pat  = Person({name:"pat",favoriteNumber:7});
    

数组的添加,跟其他语言数组的操作一样

    // 数组的添加

    function addPerson(string memory _name,uint256 _favoriteNumber) public {
       Person memory newPerson = Person(_name,_favoriteNumber);
       listOfPeople.push(newPerson);
       listOfPeople.push(Person(_name,_favoriteNumber));
    }
       // 删除人 ,是从数组最后开始删除
    function deletePerson() public {
        listOfPeople.pop();
    }
   

错误和警告

Errors & Warnings

遇到Errors & Warnings,一些搜索平台

Resources For This Course

  • AI Frens
    • ChatGPT
      • Just know that it will often get things wrong, but it's very fast!
    • Phind
      • Like ChatGPT, but it searches the web
    • Bard
    • Other AI extensions
  • Github Discussions
    • Ask questions and chat about the course here!
  • Stack Exchange Ethereum
    • Great place for asking technical questions about Ethereum
  • Peeranha
    • Decentralized Stack Exchange!

变量存储属性

5. 变量存储属性(storage/memory/calldata) 与作用域分类(状态变量、局部变量、全局变量)_海阔平的博客-CSDN博客

Memory,Storage,Calldata(Intro)

6个地方存储数据

EVM can access and store information in six places:

  1. Stack
  2. Memory
  3. Storage
  4. Calldata
  5. Code
  6. Logs

solidity中 calldata、memory、storage

目前,引用类型包括struct(结构体)、array(数组)和mapping(映射),使用引用类型必须明确地提供存储该类型的数据位置:

  memory(生存期存在于function(函数)内,超过作用域即失效);

  storage(生存期同contract(合约)一致,状态变量强制为storage);

  calldata(不可修改、非持久的函数参数存储区域,用于存储函数参数,只读,不会永久存储一个数据位置,external function(外部函数)的传入参数(不包括返回参数)强制为calldata,效果类似memory);

变量存储属性(storage/memory/calldata) 与作用域分类(状态变量、局部变量、全局变量)

Solidity中的引用类型
引用类型(Reference Type):包括数组(array),结构体(struct)和映射(mapping),这类变量占空间大,赋值时候直接传递地址(类似指针)。由于这类变量比较复杂,占用存储空间大,我们在使用时必须要声明数据存储的位置。

数据存储位置

  • storage 是默认属性,存在链上消耗gas多

  • memory和calldata存在内存消耗gas少

    • memory 的变量可修改

    • calldata的变量不可修改

solidity数据存储位置有三类:storage,memory和calldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memory和calldata类型的临时存在内存里,消耗gas少。大致用法:

storage:默认属性,合约里的状态变量默认都是storage,存储在链上。
memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。
calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。

memory 暂时存在,临时变量

    // memory 
    function addPerson(string memory _name,uint256 _favoriteNumber) public {
       _name = "cat";   //正确的,可以更改
       listOfPeople.push(Person(_name,_favoriteNumber));
    }

calldata 不能修改它

   function addPerson(string calldata _name,uint256 _favoriteNumber) public {
       _name = "cat";
       listOfPeople.push(Person(_name,_favoriteNumber));
    }



TypeError: Type literal_string "cat" is not implicitly convertible to expected type string calldata.
  --> Simple.sol:43:16:
   |
43 |        _name = "cat";
   |                ^^^^^

映射

Mappings

类似于字典

   //定义mapping
   mapping(string => uint256) public nameToNumber;
  
   function addPerson(string memory _name,uint256 _favoriteNumber) public {
       listOfPeople.push(Person(_name,_favoriteNumber));
       nameToNumber[_name] = _favoriteNumber;  //类似于字典
    }

测试部署

测试部署合约到测试网Sepolia

连接MetaMask:

用网页版,不要用本地编译环境。

EVM

类似于JVM之于Java

EVM实际上是一个标准:如何编译和如何部署智能合约到区块链。

标签:function,函数,uint256,solidity,智能,bool,address,合约,public
From: https://www.cnblogs.com/moshanghuai/p/17731926.html

相关文章

  • 大连人工智能计算中心——高性能计算平台使用指南
        ===============================================......
  • ​智能回答机器人的“智能”体现在哪里?
    人工智能的广泛应用已经成为当今社会科技发展的趋势之一。通过人工智能技术,我们可以在不同领域中实现自动化、智能化和高效化,从而大大提升生产和生活效率。智能回答机器人的出现和使用便能很好的证明这一点。今天我们就来探讨一下智能会打机器人的“智能”到底体现在哪里,以及它又能......
  • 构建智能客服知识库,优化客户体验不是难题!
    在当今快节奏的商业环境中,客户都希望得到及时个性化的支持,拥有一个智能客服知识库对于现代企业至关重要。智能客服知识库是一个集中存储、组织和访问与客户服务互动相关的信息的综合性知识库。它为企业提供了全面的知识来源,使他们能够为客户提供准确高效的支持。通过利用人工智能和......
  • 基于边缘智能网关的储充一体电站管理方案
    在“2030碳达峰,2060碳中和”的目标下,我国持续加快推进能源转型,扩大新能源占比,全国各地都在部署建设光伏、储能、新能源汽车充电等应用。随着新能源汽车的广泛普及,充电站、充电桩的需求快速增加,行业也诞生了“光伏+储能+充放”的综合能源站应用。 针对此类综合能源站的监测和管......
  • 国标GB28181安防视频平台物联网边缘的EasyGBS智能视频分析技术
    EasyGBS智能视频分析技术是一种基于图像处理和模式识别技术的视频分析方法。它通过提取视频帧中的特定特征,并利用机器学习算法对特征进行分析和比对,从而实现对视频内容的智能分析和识别。EasyGBS视频分析算法的原理主要包括以下几个方面:1.特征提取:在每一帧图像中,EasyGBS算法首......
  • 国标GB28181安防视频平台EasyGBS智能视频分析到底强在哪里?
    EasyGBS国标视频综合管理平台面向以视频为核心的智慧物联应用平台,基于分布式、负载均衡等流媒体技术,自主研发广泛兼容、安全可靠、开放共享的视频综合服务,实现视频直播、录像、回放、检索、云存储、告警上报、语音对讲、集群、智能AI分析以及平台级联共享等功能,以其直观、方便、信......
  • 孟晚舟最新发声!华为吹响人工智能的号角,发布“全面智能化”战略部署
    原创|文BFT机器人1、华为孟晚舟新发声,华为发布“全面智能化”战略上周三(9月30号)上午,华为全联接大会2023正式在上海举行,作为华为副董事长、轮值董事长、CFO的孟晚舟代表华为再次发声!在演讲上,孟晚舟提出全面智能化战略。在当前,全球智能化成为发展趋势,人工智能渗入到各行各业,各家大......
  • 国标GB28181安防视频平台EasyGBS智能视频分析技术有哪些?
    EasyGBS平台提供了友好的用户界面和操作方式,简化了系统的配置和管理过程。用户可以根据自身需求灵活配置视频分析参数和报警规则,实现个性化的视频监控管理。此外,EasyGBS平台还支持远程管理和监控,用户可以通过手机或电脑随时随地对安防系统进行远程访问和控制,提高了系统的灵活性和......
  • 什么是智能DNS?
    智能DNS(IntelligentDNS)是一种DNS(域名系统)技术,它利用智能算法和策略来管理域名解析请求,以提供更优化的域名解析体验。智能DNS的目标是根据不同的条件和需求,动态地选择最佳的DNS解析路径,以改善网络性能、可用性和安全性。以下是智能DNS的一些关键特点和概念:1、负载均衡:智能DNS......
  • 亚信科技AntDB数据库与优逸派科技基于人工智能的自动化运维管理平台产品完成兼容性互
    日前,亚信科技AntDB数据库与北京优逸派科技有限公司基于人工智能的自动化运维管理平台产品完成兼容互认。经过双方团队的严格测试,AntDB数据库与基于人工智能的自动化运维管理平台产品完全兼容,整体运行稳定高效。图1:亚信科技AntDB数据库与优逸派科技完成适配随着我国数字经济建设......