solidity基础(1)

solidity基础-1

ReadMe
测试环境:系统win10x64,solidity版本:0.4.18
声明:该笔记参考Solidity入门系列,同时我会把学习时的错误理解也写出来,然后用删除线区别

  1. 整数
    • 简介:
      • solidity支持有符号整数和无符号整数
      • 所占位数可以指定从int8/uint8int256/uint256,以8为步长,递增不同的长度;int/uint默认都是256位。
      • 整数支持数学运算符,位运算符和比较运算符
        • 数学运算符:+,-,一元+,一元-,*,/,%,**(求幂)
        • 位运算符:&,|,^,~
        • 比较运算符:<=,<,==,!=,>=,>
    • 除法截断:
      • 字面量:是一种用于表达源代码中一个固定值的表示法
      • 和其他语言一样,整数的除法运算总会被截断,例如:1/4=0,【但是使用字面量的方式则不会截断,例如:var e = 1/4,当然可能也是var本身就具有智能推断的功能】此段待商榷
    • 移位:
      • 左移<<:相当于乘法,和C语言中的用法相同
      • 右移>>:相当于除法,和C语言中的用法相同
      • 所以:移位并不会改变符号位
      • 注意:右移最小是0,例如:1>>4=0
    • 异常:除以0或者对0取模,对一个值移负数位都会报异常
    • 溢出:
      • 上溢:如果一个整型变量的值达到其类型的上限,再给它加上一个正数,最终结果会是(变量值 + 正数) - 类型上限
      • 下溢:如果一个整型变量的值达到其类型的下限,再减去一个正数,会变成它的上限值-该正数的值

  2. 地址
  • 对比:以太坊提供的是账户模型,而比特币提供的是UTXO模型
  • 地址(address):
    • 一个地址代表一个账户,账户可以是普通的个人账户,也可以是包含代码的合约账户;因此在某些时候,地址代表的是一份合约代码
    • 长度:固定20字节
    • 支持的操作符:<=,<,==,!=,=,>
    • 成员:
      • balance:查询地址的余额,可以用this.balance来直接查询当前合约的余额,类型为uint
      • send:使用send()来向某个地址转账(货币单位是wei)
      • call(),callcode(),delegatecall():支持传入任意类型的任意参数来直接与合约进行交互
  • 参考资料:
    • balance和send
    • call等

  1. 以太币支付
    • payable标识符:
      • 函数上增加payable标识,即可接收ether,并会把ether存在当前合约
    • send()函数发送ether
      • 地址对象中的send()可以向某地址直接进行支付
        • 如果是普通地址将会直接收到
        • 但是合约要接收通过send()函数发送的ether,会有限制
          1. 如果我们要在合约中通过send()函数接收,就必须定义fallback函数,否则会抛异常
          2. fallback函数必须增加payable关键字,否则send()执行结果将会始终为false
    • 支付中可能的失败
      • send()失败
        1. 由于调试者可以强制指定调用堆栈的深度,当调用的栈深超过指定值时,一般为1024
        2. 接收地址处理支付过程中out of gas,即gas不够时
      • 合约的fallback()
        如果是合约地址,在执行send()时,默认关联执行fallback(),这是EVM的默认行为,不可阻止,所以这个函数引起的失败,交易会被撤销,send()为false

        EVM:以太坊虚拟机,参考资料
      • payable标识
        如果一个函数要进行货币操作,必须带上payable关键字,这样才能正常接收msg.value
    • 参考资料:
      • 原文参考
      • payable资料

  2. 定长字节数组
    • 简介:
      • 定义定长字节数组的方式是bytesN,N的取值范围1~32byte默认标识bytes1
      • 定长字节数组的步长为1,整数类型的步长为8
    • 定义新变量
      定义新变量时可以使用整数字面量,或者字符串字面量
      • bytes1 a = 255;
      • byte a = "a";
      • 用整数字面量定义时,注意取值范围,如:byte整数范围为-128~255
    • 运算符:
      • 比较运算符有<=,<,==,!=,>,=>,返回的结果为bool类型
      • 位运算符:&,|,^,~,<<,>>
        移位操作符的右值必须为整数,移位操作同样也要注意越界问题,越界会抛异常;如:byte a = 'a' << 1,会报错,但是可以byte b = 'a';byte a = b << 1这样通过中间变量来避免报错
      • 不支持数学运算符
    • 使用序号访问定长字节数组:
      可以使用序号来访问定长字节数组的某个字节;但是序号的取值不能超过定长字节数组的长度,和数组类似
    • 长度:
      定长字节数组提供了一个只读属性.length来查看其长度,.length的返回值类型是uint8

  3. 函数
    • 关键字:function,类似于go语言中的func

    • 函数的参数:类似于C语言的函数参数,同样分实参和形参

    • 命名参数:函数调用可以使用命名参数,将参数名和参数值这样的键值对以任意顺序放进{}即可,类似于go语言中的map

       function f(uint k,uint v) returns(uint,uint) {
           return (k,v);
       }
       function g() returns(uint,uint) {
         return f({v:2,k:1});
       }
      
    • 函数的返回值:

      • 返回值的定义与参数类似,跟在returns之后即可,如果在返回值中已经定义了变量,可以不调用return,直接返回变量即可

        function f(uint a,uint b) returns(uint r) {
           r = a + b;
         }
        
      • return关键字:和其他语言类似

    • 函数的高级特性:
      函数还支持跨合约函数调用的可见性控制,函数级别货币支付支持,函数级的访问控制等独有特性

  4. 函数的可见性与访问权限控制
    • 简介:
      介绍solidity作为一个分布式网络语言所特有的internalexternal这两种不同的函数调用方式,以及solidity提供的对函数调用的可见性控制语法
    • 调用方式:
      1. internal:
        internal调用,实现时转为简单的EVM跳转,所以可以直接使用上下文环境中的数据,对于引用传递时将会变得非常高效
        在当前的代码单元内,如对合约内函数,引入的库函数,以及父类合约中的函数直接使用即是以internal方式的调用

         pragma solidity ^0.4.18;
         contract Test {
         function f() {}
         //以internal的方式调用
         function call() {
           f();
           }
         }
        
      2. external:

        external调用,实现为合约的外部消息调用,所以在合约初始化时不能以external的方式调用自身函数,因为合约还未初始化完成

         pragma solidty ^0.4.18;
         //contract afunction
         contract Afunction {
           //function f(uint k) external returns
           function f(uint k) returns(uint r) {
             r = k;
           }
         }
        
         contract bfunction {
           //以external的方式调用另一合约中的函数
           //function callAfunction(afunction a)
           function callAfunction(Afunction a) {
             a.f(4);
           }
         }
        

        和go语言一样,合约的首字母必须为大写才可以被外部合约调用;如果不大写的话,就必须为函数加上external,不然不能调用
        external调用时,实际是向目标合约发送一个消息调用。消息中的函数定义部分是一个24字节大小的消息体,20字节为地址,4字节为函数签名

      3. this
        我们可以在合约的调用函数前加this.来强制以external的方式调用,需要注意的是,这里的this的用法与大多数语言都不一致。
        当然,我们回到上面看一下external的说明,在合约初始化时不能以external的方式来调用自身函数,所以强制调用会报错,这也从反方面说明this.的确是以external方式调用

      4. 调用方式说明:
        上面所提到的internalexternal指的是函数调用方式,请不要与后面的函数可见性声明:external,public,internal,pravite弄混,声明只是意味着这个函数需要使用相应的调用方式去调用。后续说明中会用以某某方式调用,来强调是对调用方式的阐述以加以区分

    • 函数的可见性
      • 简介:solidity为函数提供了四种可见性:external,public,internal,pravite

      • external:

        • 声明为external的函数可以从其他合约或通过Transaction进行调用,所以声明为external的函数是合约对外接口的一部分
        • 不能以internal的方式进行调用
        • 有时在接收大的数据数组时性能更好

          声明为external的函数只能以external的方式进行调用;在同一个合约中调用声明为external的函数,要用this.强制调用,以internal的方式调用会报错
      • public:

        • 函数默认声明为public

        • pubic的函数允许以internal的方式调用,也允许以external的方式调用

        • public的函数由于被外部合约访问,所以是合约对外接口的一部分

           pragma solidity ^0.4.18;
           contract FunctionTest {
             function publicFunc() {}
          
             function callFunc() {
               //以internal的方式调用
               publicFunc();
               //以external的方式调用
               this.publicFunc();
             }
           }
          
      • internal:

        • 在当前的合约或继承的合约中,声明为internal的函数只允许以internal的方式调用

           pragma solidity ^0.4.18;
           contract functionTest {
             //默认是public函数
             function internalFunc() internal{}
             function callFunc() {
               //当前函数中的调用
               internalFunc();
             }
           }
          
           //solidity中用contract B is A
           //来表示,B是A的继承
           contract functionTest1 is functionTest {
             function callinernalFunc() {
               //子合约中的调用
               internalFunc();
             }
           }
          
      • pravite:

        • 只能在当前合约中被访问(不可以在继承合约中访问)
        • 即使声明为private,仍能被所有人查看到里面的数据;访问权限只是阻止了其它合约访问函数或修改数据

你可能感兴趣的:(solidity基础(1))