Solidity语法规范整理

一、Solidity 是什么

  • Solidity是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了C++,Python和JavaScript语言的影响,设计的目的是能在以太坊虚拟机(EVM)上运行。
  • Solidity 是静态类型语言,支持继承、库和复杂的用户定义类型等特性。
  • 内含的类型除了常见的编程语言的标准类型,还包括address等以太坊独有的类型,Solidity源码文件通常以sol作为扩展名。
  • 目前尝试Solidity编程最好的方式是使用Remix。Remis是一个基于Web浏览器的IDE,它可以让你编写Solidity智能合约,然后部署并运行该智能合约。

二、Solidity语言特性

 Solidity的语法接近于JavaScript,是一种面向对对象的语言。但作为一种真正意义上裕兴在网络上的去中心化合约,它又有很多的不同:

  • 以太坊底层基于账户,而不是UTXO,所以增加了一个特殊的address的数据类型用于定义用户和合约账户。
  • 语言内嵌框架支持支付。提供了payable等关键字,可以在语言层面直接支持支付。
  • 使用区块链进行数据的存储。数据的每一个状态都可以永久存储,所以在使用时需要确定变量使用内存,还是区块链存储。
  • 运行环境是在去中心化的网络上,所以需要强调合约或函数执行的调用方式。
  • 不同的异常机制。一旦出现异常,所有的执行都将会被回撤,这主要是为了保证合约执行的原子行,以避免中间状态出现的数据不一致。

三、Solidity源码和智能合约

Solidity源代码要成为可以运行在以太坊上的智能合约需要经历如下的步骤:

  1. 用Solidity编写的只能合约源代码需要先使用编译器编译为字节码(Bytecode),编译过程中会同时产生智能合约的二进制接口规范(Application Binary Interface,简称ABI)。
  2. 通过交易(Transaction)的方式将字节码部署到以太坊网络,每次成功部署都会产生一个新的智能合约账户。
  3. 使用Javascript 编写的Dapp通常通过web3.js + ABI去调用智能合约中的函数来实现数据的读取和修改。

四、Solidity编译器

        Remix

  • Remix是一个基于Web浏览器的Solidity的IDE,可以在线使用而无需安装任务东西。
  • http://remix.ethereum.org

        solcjs

  • solc是Solidity源码库的构建目标之一,她是Solidtiy的命令行编译器
  • 使用npm 可以便捷地安装Solidtity编译器solcjs
  • npm install -g solc

五、一个简单的数据存储智能合约

pragma solidity >=0.7.0 <0.9.0;

contract SimpleStorage {
    uint myData;
    
    function setMyData(uint newData) public {
        myData = newData;
    }
    
    function getMyData() public view returns(uint) {
        return myData;
    }
}

通过Remix和MetaMask可以直接进行编译和部署

 在部署后,可以在Remix中直接调用函数进行结果测试。

六、Solidity一个子货币案例

// 设置solidity版本
pragma solidity >=0.7.0 <0.9.0;

// contract 关键字定义合约 ,类似于java中的calss
contract Coin{
    // address是solidity中的特殊的数据类型
    address public mointer;
    
    mapping(address => uint) banlances;
    
    event Sent(address from, address to, uint amount);
    
    constructor(){
        mointer = msg.sender;
    }
    
    function mint(address receiver,uint amount) public {
        require(mointer == msg.sender);
        banlances[receiver] += amount;
    }
    
    function send(address receiver, uint amount) public {
        require(amount <= banlances[msg.sender]);
        banlances[msg.sender] -= amount;
        banlances[receiver] += amount;
        // emit Sent(msg.sender, receiver, amount);
    }
    
    function getBanlance(address viewer) public view returns(uint) {
        return banlances[viewer];
    }
}

七、Solidity源文件布局

 1、pragma(版本杂注)

  • 源文件可以被版本杂注pragma所注解,表明要求的编译器版本
  • 例如:pragma solidtiy ^0.4.0;
  • 源文件将既不允许低于0.4.0版本的编译器编译,也不允许高于(包含)0.5.0版本的编译器编译(第二个条件因使用^被添加)

2、import (导入其它源文件)

 Solidity所支持的导入语句import,语法同JavaScript非常类似。

八、Solidity值类型

  • 布尔(bool):可能的取值为字符常量值true或false
  • 整型(int/uint):分别表示有符号和无符号的不同位数的整型变量;支持关键字uint8到uint256(无符号,从8位到256位)以及int8到int256,以8位为步长递增。
  • 定长浮点类型(fixed/ufixed):表示各种大小的有符号和无符号的定长浮点型。在关键字ufixedMxN 和fixedMxN 中,M表示该类型占用的位数,N表示可用的小数位数。
  • 地址(address): 存储一个20字节的值(以太坊地址大小)
  • 定长的字节数组:关键字有bytes1,bytes2,bytes3,...,bytes32。
  • 枚举(enum):一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用来模拟合约的状态。
  • 函数(function):一种表示函数的类型。


九、Solidity引用类型

1、数组(Array)

数组可以在声明时指定长度(定长数组),也可以动态调整大小(变长数组、动态数组);

对于存储(storage)的数组来说,元素类型可以是任意的(即元素可以数组类型、映射类型或者结构体);对于内存型(memory)的数组来说,元素类型不能是映射(mapping)类型的

2、结构(struct)

Solidity支持通过Struct新的结构体的形式定义新的类型。相当于Java中的实体类的概念。

3、映射(Mapping)

类似于Java中的Map, 映射可以视作哈希表,在实际的初始化过程中创建每个可能的key,并将其映射到字节形式全是零的值(类型默认值)。

十、Solidity地址类型

1 address

地址类型存储一个20字节的值(以太坊地址的大小);地址类型也有成员变量,并作为所有合约的基础。

2、address payable(0.5.0引入)

与地址类型基本相同,不过多出了transfer 和 send两个成员变量。

3、两者区别和转换

  • Payable地址是可以发送ehter的地址,而普通address不能。
  • 允许从payable address到address的隐私换砖,而反过来的直接转换是不可能的(在0.7.0版本中可以通过payable 进行中间转换)
  • 从0.5.0版本起,合约不再是从地址类型派生而来,但如果它有payable的回退函数,那同样可以显式转换Wieaddress 或者address payable类型。

十一、地址类型成员变量

       1、 <address>.balance

         获取该地址的ether余额, 以wei为单位。

        2、<address payable>.transfer(uint256 amount)

        向指定地址发送数量为amount 的ether(以wei为单位),失败时抛出异常,发送2300 gas的矿工费,不可调节。谁调用transfer 就给谁发币。

        3、<adress.payable>.send(uint256 amount )returns(bool)

                向指定地址发送数量为amount的ether(以wei为单位),失败时返回false,发送2300gas旷工费用,不可调节。

        4、<address>.call(bytes memory)returns(bool,bytes memory)

                发出底层函数调用call,失败时返回false,发送所有可用gas,可调节

        5、<address>.delegatecall(bytes memory)

                发出底层函数调用call,失败时返回false,发送所有可用gas,可调节

        6、<address>.staticcall(bytes memory)

         发出底层函数调用call,失败时返回false,发送所有可用gas,可调节

十二、地址成员变量用法:

1、balance和transfer

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

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

2、send

      send是transfer的低级版本,如果执行失败,当前的合约不会因为异常而终止,但send会返回false。

3、call

        也可以用call来实现抓币的操作,通过添加gas()和value()修饰器。

nameReg.call.gas(1000000).value(1 ether)("register", "MyName");

call函数都属于低级函数,需要谨慎使用。 具体来说,任何未知的合约都可能是恶意的。 你在调用一个合约的同时就将控制权交给了它,它可以反过来调用你的合约, 因此,当调用返回时要为你的状态变量的改变做好准备。

十三、函数可见性修饰

   由于Solidity有两种函数调用方式,内部调用和外部调用。内部调用不会产生实际的EVM调用活称为消息调用,而外部调用则会产生一个EVM调用。函数和状态变量有四种可见性类型。函数可以指定为external、public、internal、或者private,默认情况下函数类型为public。对于状态变量,不能设置为external,默认为internal。

1、external:

       函数只能通过合约外的函数调用,不能通过本合约内的函数调用。

2、public:

        public函数是合约接口的一部分,任何合约都可以调用。对于public修饰的状态变量,会自动生成一个getter函数。

3、internal:

         internal修饰的函数和状态变量只能在内部访问,不适用this调用。

4、private

        private修饰的函数和状态变量仅在当前合约中使用,并且不能被派生合约 使用。

十四、函数状态类型

   1、view函数

        可以将函数声明为view类型,被view修饰的函数要保证不修改状态。

     2、Pure函数(纯计算)

        函数可以声明为Pure,在这种情况下,承诺不读取或修改装填。

    3、Fallback函数

        合约可有一个未命名的函数。这个函数不能有参数也不能有返回值。如果在一个合约的调用中,没有其他函数与给定的函数标识符匹配,那么这个函数(fallback 函数)会被执行。

        除此之外,每当合约收到以太币(没有任何数据),这个函数就会执行。此外为了接收以太币,fallback函数必须标记为payable。如果不存在这样的函数,则合约不能通过常规交易接收以太币。

        在这样的上下文中,通常只有很少的gas可以用来完成这个函数调用(准确的说,是2300gas),所以使fallback函数的调用尽量廉价很重要。请注意,调用fallback函数的交易,(而不是内部调用)所需的gas要高的多,因为每次交易都会额外收取21000 gas或更多的费用,用于签名检查等操作。(这里不明白什么意思)

十五、函数修饰器

  使用修饰器可以轻松改变函数的行为。例如,他们可以在执行函数之前自动检查某个条件。修饰器是合约的可集成属性,并可能被派生合约覆盖。

pragma solidity ^0.4.11;

contract owned {
    function owned() public { owner = msg.sender; }
    address owner;

    // 这个合约只定义一个修饰器,但并未使用: 它将会在派生合约中用到。
    // 修饰器所修饰的函数体会被插入到特殊符号 _; 的位置。
    // 这意味着如果是 owner 调用这个函数,则函数会被执行,否则会抛出异常。
    modifier onlyOwner {
        require(msg.sender == owner);
        //  _是一个占位符
        _;
    }
}

contract mortal is owned {
    // 这个合约从 `owned` 继承了 `onlyOwner` 修饰符,并将其应用于 `close` 函数,
    // 只有在合约里保存的 owner 调用 `close` 函数,才会生效。
    function close() public onlyOwner {
        selfdestruct(owner);
    }
}

有的语法在新版本中会有出入,后面还有新增会持续添加...

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

taojin12

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值