全面掌握Solidity智能合约开发

2024年09月25日更新 796 人订阅
原价: ¥ 46 限时优惠
专栏简介 跟我学 Solidity :开发环境 跟我学 Solidity:关于变量 跟我学 Solidity : 变量的存储 跟我学 Solidity :引用变量 跟我学 Solidity :函数 跟我学 Solidity :合约的创建和继承 跟我学 Solidity :工厂模式 用Web3.js构建第一个Dapp 跟我学Solidity:事件 Solidity 中 immutable (不可变量)与constant(常量) [译] Solidity 0.6.x更新:继承 解析 Solidity 0.6 新引入的 try/catch 特性 探究新的 Solidity 0.8 版本 探索以太坊合约委托调用(DelegateCall) 停止使用Solidity的transfer() 使用工厂提高智能合约安全性 Solidity 怎样写出最节省Gas的智能合约[译] Solidity 优化 - 编写 O(1) 复杂度的可迭代映射 Solidity 优化 - 控制 gas 成本 Solidity 优化 - 减少智能合约的 gas 消耗的8种方法 Solidity 优化 - 如何维护排序列表 Solidity 优化:打包变量优化 gas 使用 Solidity 瞬态存储操作码 在 Solidity中使用值数组以降低 gas 消耗 Gas 优化:Solidity 中的使用动态值数组 计算Solidity 函数的Gas 消耗 Solidity 技巧:如何减少字节码大小及节省 gas 一些简单的 Gas 优化基础 "Stack Too Deep(堆栈太深)" 解决方案 智能合约Gas 优化的几个技术 合约实践:避免区块Gas限制导致问题 如何缩减合约以规避合约大小限制 Solidity 类特性 无需gas代币和ERC20-Permit还任重而道远 智能合约实现白名单的3个机制 Solidity智能合约安全:防止重入攻击的4种方法 Solidity 十大常见安全问题 [译]更好Solidity合约调试工具: console.log 智能合约开发的最佳实践 - 强烈推荐 全面理解智能合约升级 Solidity可升级代理模式: 透明代理与UUPS代理 使用OpenZeppelin编写可升级的智能合约 实战:调整NFT智能合约,减少70%的铸币Gas成本 Solidity 优化 - 隐藏的 Gas 成本 Gas 技巧:Solidity 中利用位图大幅节省Gas费 Solidity Gas 优化 - 理解不同变量 Gas 差异 关于Solidity 事件,我希望早一点了解到这些 Solidity 编码规范推荐标准 深入了解 Solidity bytes OpenZeppelin Contracts 5.0 版本发布 Solidity Gas优化:高效的智能合约策略 智能合约安全的新最低测试标准:Fuzz / Invariant Test 智能合约的白名单技术 模糊测试利器 - Echidna 简介 智能合约设计模式:代理 离线授权 NFT EIP-4494:ERC721 -Permit

跟我学 Solidity:关于变量

开始在以太坊上编写智能合约

欢迎来到跟我学习Solidity系列中的第二篇文章。如果你还没有阅读第一篇:Solidity入门,我强烈建议你这样做以设置开发环境以及编写和部署第一个合约。 在本文中,我们将研究Solidity中的变量,它们的类型,它们的存储方式以及如何使用它们。

Solidity中,我们有两种类型的变量:

状态变量

这些变量在函数外部声明(例如类的属性),并永久存储在以太坊区块链中,更具体地说存储在存储Merkle Patricia树中,这是形成帐户状态的信息的一部分(这就是为什么我们称其为状态变量)。

diagram of Merkle Patricia tree

以太坊Merkle Patricia树:来源

你可以找到有关数据存储在以太坊区块链中的更多信息,参考文章.

状态变量可以在声明时进行初始化,并且具有以下可见性:

  • private:状态变量仅在定义的合约里可见。
  • public:状态变量也可以在定义合约的外部访问,因为编译器会自动创建一个与该变量同名的getter函数。
  • internal:状态变量在定义的合约以及所有继承合约都是可见的。

可见性指示符放在状态变量的类型之后,如果未指定,则状态变量将被视为internal

局部变量

这些是在函数内部声明的变量,其作用域限定在声明它们的代码块内。

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.7.0;

contract HelloWorldContract {

    address owner; // 状态变量

    function helloword() external pure returns(string memory){

        string memory  greeting ="hello world"; // 局部变量

        return greeting;
    }

}

与其他任何语言一样,我们有基本数据类型和复杂数据类型。当用作函数参数或在赋值中时,基本数据类型始终按值传递,而复杂数据类型(如数组和结构体)则按引用传递。

基本数据类型

table of Solidity elementary data types and what each may contain

Solidity 基本数据类型

有关地址类型的更多信息:

  • 地址字面常量:通过地址校验和测试的十六进制字面常量,例如0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF属于address payable类型。
  • 类型转换:address payable可以隐式转换为简单的address类型,这表示你可以将address payable分配给address类型,而无需显式转换。

整数字面常量bytes20,可以使用以下语法:address(x)进行显式转换为地址。这种转换将产生address payable类型。

  • 地址类型成员:地址类型的两个重要成员是balance(允许查询地址的余额)和transfer(允许发送以wei单位的以太币到address payable类型的地址。
  • 合约和地址类型: 你可以使用之前看到的语法将合约明确转换为地址类型:address(x),其中x是合约的一个实例。如果合约定义了receive函数或fallback function函数(我们后面会介绍这两个函数的更多详情),则会转换为address payable,如果没有这两个函数,则转换为address,此时,如果你希望转换为payable,则必须使用payable(address(x))

全局可用变量

全局命名空间中始终存在一些特殊变量,这些变量主要用于提供有关区块链的信息。

我们可以将这些变量分为三类:

  1. 区块属性

table of block types and what each main contain

  1. 消息属性

table of message types and what each may contain

  1. 交易属性

table of transaction types and what each may contain

我们将大量使用的两个属性是msg.sendermsg.valuemsg.sender可以向我们提供发送方的地址,从而可以保存合约所有者的地址,而msg.value则可以获取发送的金额。

举个例子(练习),我们保存合约创建者的地址并修改HelloWorldContract,这样,如果交易信息是由创建者发送的,我们将用hello Daddy向他们打招呼(编写sayHello方法)。否则,我们向发送者打招呼hello world

pragma solidity ^0.7.0;

contract HelloWorldContract {

  address owner; // 状态变量

  constructor() {
      owner = msg.sender;
  }

  function sayHello() external pure returns(string memory){
      if(owner==msg.sender) {
        return "hello Daddy";
      }

      string memory  greeting ="hello world"; // 局部变量

      return greeting;
  }

}

按照我们在上一篇文章中看到的那样部署合约,然后单击sayHello,你将得到hello Daddy,因为你用于部署合约的地址与你用来调用该合约的地址相同功能。

让我们更改帐户,然后再次调用该功能。为了更改你的帐户,你需要单击“帐户”部分的下拉列表,然后选择其他地址。

Image for post

如果这次调用sayHello,你应该会得到hello world。 太好了,我们学到了一些东西。

在练习应用所学知识之前,我想提到一下,Solidity中的this关键字引用了当前合约的类型,并且可以明确转换为地址,正如我们在合约实例中看到的那样。

本文要结束了,尝试下完成以下作业:

  • 获取合约的地址。
  • 获取合约所有者的地址。
  • 获取发送者的地址。
  • 获取合约余额。
  • 获取合约所有者的余额(仅当发送者是所有者时)。
  • 获取发送者的余额。

你可以在GitHub上找到解决方案.

希望你喜欢这篇文章。下次,我们将讨论复杂的类型,并揭示上一代码中我在string旁边使用的memory关键字背后的奥秘。因此,如果你想了解更多信息,请坚持学习,并在下一篇文章中见。


本翻译由 Cell Network 赞助支持。

点赞 14
收藏 3
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

4 条评论

请先 登录 后评论