Solidity是一门专为实现智能合约而创建的高级编程语言,在以太坊虚拟机EthereumVirtualMachine(EVM)上运行。它与C,Python以及JavaScript颇有渊源。 比较重要的特性:提供payable等关键字,在语言层面支持支付提供address数据类型,用于定位用户和合约账号使用区块链进行数据存储。任何数据的每一个状态都可以永久存储,因此使用时需要注意确定变量是使用内存还是使用区块链存储一旦出现异常,所有的执行都会被撤销,以确保合约执行的原子性,保证数据一致性一个简单的例子SPDXLicenseIdentifier:GPL3。0pragmasolidity0。7。00。9。0;contractBasicTest{uintmyStoredData;functionmyGet()publicviewreturns(uint){returnmyStoredData;}functionmySet(uintwhat)public{myStoredDatawhat;}} 代码编译部署到区块链上之后,任何人只要知道了该合约的地址及函数签名,都可以修改myStoredData数据。比如,该合约地址为0xaE036c65C649172b43ef7156b009c6221B596B8b那么编写如下代码:SPDXLicenseIdentifier:GPL3。0pragmasolidity0。7。00。9。0;interfaceBasicTest{functionmyGet()externalviewreturns(uint);functionmySet(uintw)external;}contractSuper{BasicTestbt;functionsetAddr(BasicTestaddr)public{btaddr;}functiontest(uintw)publicreturns(uint){bt。mySet(w);returnbt。myGet();}} 输入参数为合约地址,执行setAddr;然后输入欲改值1356,就可以修改了。 数据类型 布尔bool,整型intuint,定长fixedufixed,地址address,定长字节数组,变长字节数组,枚举 需要说明的是:整型支持关键字uint8到uint256,int8到int256。可调配的选择项非常丰富,这对于在资源消耗相对敏感的区块链环境中很重要。同理,还有定长数组,包括bytes1,bytes2,bytes3,。。。,bytes32。地址类型拥有成员变量balance和transfer。如果你之前没有了解过Solidity,是不是觉得这个特性相当amazing;)她的确就是的,这给交易提供了天然的支持。函数function(parametertypes){internalexternal}〔pureconstantviewpayable〕〔returns(returntypes)〕 函数的可见性 可指定为external,public,internal,或者private 对于public和private,相信学过其他高级语言的人都能明白:public修饰的变量和函数,任何用户或者合约都能调用和访问。private修饰的变量和函数,只能在其所在的合约中调用和访问,即使是其子合约也没有权限访问。internal和private类似,不过,如果某个合约继承自其父合约,这个合约即可以访问父合约中定义的内部函数。external与public类似,只不过这些函数只能在合约之外调用它们不能被合约内的其他函数调用。 函数的状态可变性pure:纯函数,不允许修改或访问状态view:不允许修改状态payable:允许从消息调用中接收以太币Etherconstant:与view相同,一般只修饰状态变量,不允许赋值(除初始化以外) 如果你试图在一个用view或者pure修饰的函数体内修改变量,或者在一个未使用payable修饰的函数体内发送ether,那么编译的时候,就会给出错误。内部函数调用 仅仅发生在一个合约内部。可以理解为方法调用。外部函数调用 外部函数调用使用消息机制实现。外部调用事件消息包括了发送者,接收者,内容,ether数量,以及gas。 一个合约调用其它合约的函数,只有通过外部函数调用的方式,没有其它方式。 调用一个public函数,分别使用内部调用和外部调用,对比一下: 内部调用functiong1(uinta)publicreturns(uintret){return44;}functiony2()publicreturns(uintret){uintag1(100);for(uinti0;i30;i){g1(100);}returna;} 外部调用functiong1(uinta)publicreturns(uintret){return44;}functiony1()publicreturns(uintret){uintathis。g1(100);for(uinti0;i30;i){this。g1(100);}returna;} 可以看出,所消耗的gas差别很大。 进一步试验contractFunctionTest{uintpublicv1;uintpublicv2;functioninternalFunc()internal{v110;}functionexternalFunc()externalreturns(uintres){v220;returnv2;}functionresetV2()public{v20;}functioncallFunc()public{直接使用内部的方式调用internalFunc();合约内部直接调用,正确不能在内部调用一个外部函数,会报编译错误。Error:Undeclaredidentifier。externalFunc();外部合约不可以调用不能通过external的方式调用一个internalMemberinternalFuncnotfoundornotvisibleafterargumentdependentlookupincontractFuntionTestthis。internalFunc();this。相当于外部调用使用this以external的方式调用一个外部函数this。externalFunc();}}合约的继承contractSonisFunctionTest{functioncallInternalFunc()public{internalFunc();可以继承父合约的内部方法this。externalFunc();}}contractFunctionTest1{uintpublicv3;functionexternalCall(FunctionTestft)public{调用另一个合约的外部函数v3ft。externalFunc();不能调用另一个合约的内部函数Error:MemberinternalFuncnotfoundornotvisibleafterargumentdependentlookupincontractFuntionTestft。internalFunc();}functionresetV3()public{v30;}} 最后,再看一个发送ether的例子。可以指定gas。具体如何估算,留个悬念,请见下回分解吧。functiong(uinta)publicpayablereturns(uintret){return44;}functiony()publicpayablereturns(uintret){uintathis。g{value:11,gas:5800}(100);returna;}constructor()payable{}必不可少 注意:payable关键字