Solidity基础语法、关键字

本文详细介绍了Solidity编程语言的基础语法和关键字,包括版本指令、合约创建、状态变量、无符号整数、数学运算、结构体、数组、函数定义、函数修饰符、散列函数、类型转换、事件、地址、映射、消息发送者(msg.sender)、需求(require)、继承、引入、存储与内存、函数可见性以及构造函数等核心概念,旨在帮助开发者深入理解以太坊智能合约开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、版本指令:pragma solidity ^x.x.xx;
pragma solidity >=0.5.0 <0.6.0;
//在本示例的范围内,我们希望能够使用0.5.0(包括)到 0.6.0(不包括)范围内的任何编译器版本来编译我们的智能合约。

所有 Solidity 源代码都应该以“版本编译指示”开头——该代码应该使用的 Solidity 编译器版本的声明。这是为了防止未来编译器版本的问题可能会引入会破坏您的代码的更改。
总而言之,这是一个基本的起始合同——每次开始一个新项目时你要写的第一件事。

二、合约创建:contract xxx { … }
contract HelloWorld {
   
   
  ....
}

Solidity的代码都封装在contracts中。contract是以太坊应用程序的基本构建块,所有变量和函数都属于一个合约,这将是你所有项目的起点。

三、状态变量
contract Example {
   
   
  //这将永久存储在区块链中 
    uint myUnsignedInteger = 100;
}

状态变量永久存储在合约存储中。这意味着它们被写入以太坊区块链。把它们想象成写数据库。
在示例中,定义 myUnsignedInteger 为 uint 类型并将其设置为 100。

四、无符号整数:uint

uint 无符号数据类型, 指其值不能是负数,对于有符号的整数存在名为 int 的数据类型。

注: Solidity中, uint 实际上是 uint256代名词, 一个256位的无符号整数。你也可以定义位数少的无符号整数 — uint8, uint16, uint32, 等…… 但一般来讲你愿意使用简单的 uint, 除非在某些特殊情况下,这我们后面会讲。

五、数学运算(加减乘除、乘方)
加法:x+y
减法:x-y
乘法:x*y
除法:x/y
Solidity 还支持 乘方操作 (如:x 的 y次方) // 例如: 5 ** 2 = 25
uint x = 5 ** 2; // equal to 5^2 = 25
六、结构体:struct
struct Person {
   
   
  uint age;
  string name;
}

结构体允许你生成一个更复杂的数据类型,它有多个属性。

注:我们刚刚引进了一个新类型, string。 字符串用于保存任意长度的 UTF-8 编码数据。 如: string greeting = “Hello world!”。

七、数组

如果你想建立一个集合,可以用数组这样的数据类型. Solidity 支持两种数组: 静态数组和动态数组:

静态数组
// 固定长度为2的静态数组:
uint[2] fixedArray;
// 固定长度为5的string类型的静态数组:
string[5] stringArray;
// 动态数组,长度不固定,可以动态添加元素:
uint[] dynamicArray;
动态数组

你也可以建立一个 结构体类型的数组 例如,(六、结构体中提到的) Person:

Person[] people; // 这是动态数组,我们可以不断添加元素

记住:状态变量被永久保存在区块链中。所以在你的合约中创建动态数组来保存成结构的数据是非常有意义的。

公共数组

你可以定义 public 数组, Solidity 会自动创建 getter 方法. 语法如下:

Person[] public people;

其它的合约可以从这个数组读取数据(但不能写入数据),所以这在合约中是一个有用的保存公共数据的模式。

八、定义函数
function eatHamburgers(string _name, uint _amount) {
   
   

}

这是一个名为 eatHamburgers 的函数,它接受两个参数:一个 string类型的 和 一个 uint类型的。现在函数内部还是空的。

注:: 习惯上函数里的变量都是以(_)开头 (但不是硬性规定) 以区别全局变量。我们整个笔记都会沿用这个习惯。

调用函数示例:

eatHamburgers("vitalik", 100);
九、使用结构体和数组
struct Person {
   
   
  uint age;
  string name;
}

Person[] public people;

现在我们创建新的 Person 结构,然后把它加入到名为 people 的数组中.

// 创建一个新的Person:
Person satoshi = Person(172, "Satoshi");

// 将新创建的satoshi添加进people数组:
people.push(satoshi);

你也可以两步并一步,用一行代码更简洁:

people.push(Person(16, "Vitalik"));

注:array.push() 在数组的 尾部 加入新元素 ,所以元素在数组中的顺序就是我们添加的顺序, 如:

uint[] numbers;
numbers.push(5);
numbers.push(10);
numbers.push(15);
// numbers is now equal to [5, 10, 15]
十、私有 / 公共函数

Solidity 定义的函数的属性默认为public。 这就意味着任何一方 (或其它合约) 都可以调用你合约里的函数。

显然,不是什么时候都需要这样,而且这样的合约易于受到攻击。 所以将自己的函数定义为private是一个好的编程习惯,只有当你需要在外部调用它时才将它设置为public。

如何定义一个私有的函数呢?

uint[] numbers;

function _addToArray(uint _number) private {
   
   
  numbers.push(_number);
}

这意味着只有我们合约中的其它函数才能够调用这个函数,给 numbers 数组添加新成员。

可以看到,在函数名字后面使用关键字 private 即可。和函数的参数类似,私有函数的名字用(_)起始。

十一、返回值:returns

Solidity 里,函数的定义里可包含返回值的数据类型(如本例中 string)。

string greeting = "What's up dog";

function sayHello() public 
### Solidity 中 `virtual` 关键字的作用与使用场景 #### 1. 定义可被重写的函数 在 Solidity 中,`virtual` 关键字用于标记一个函数可以被派生合约所重写。这类似于其他面向对象编程语言中的概念,比如 C++ 或 Java 的虚函数机制。只有当函数被显式地标记为 `virtual` 时,它才能在其子合约中被覆盖[^1]。 ```solidity contract Base { function foo() public virtual returns (string memory) { return "Base"; } } ``` 在此示例中,`foo()` 方法被声明为 `virtual`,因此任何继承自 `Base` 合约的子合约都可以对该方法进行重新定义。 #### 2. 使用 `override` 明确指定重写 为了增强代码的清晰性和安全性,在派生合约中重写父级的虚拟函数时,建议使用 `override` 关键字来表明意图。这是 Solidity 推荐的最佳实践之一,有助于防止意外的行为或错误。 ```solidity contract Child is Base { function foo() public override returns (string memory) { return "Child"; } } ``` 这里展示了一个名为 `Child` 的新合约,该合约从 `Base` 继承而来并提供了自己的 `foo()` 实现版本。 #### 3. 支持多重继承下的复杂交互 当涉及到多个基类或者复杂的继承结构时,`virtual` 和 `override` 结合起来能够很好地管理不同层次间的相互关系。例如: ```solidity abstract contract InterfaceA { function bar() public virtual returns (string memory); } abstract contract InterfaceB { function bar() public virtual returns (string memory); } contract Implementation is InterfaceA, InterfaceB { function bar() public override(InterfaceA, InterfaceB) returns (string memory) { return "Implementation"; } } ``` 在这个例子中,两个独立接口都要求实现同一个名称的方法 `bar()` 。通过运用 `virtual` 及相应的 `override` 声明,我们可以满足这些需求而不引发冲突。 #### 4. 配合修饰符(Modifiers) 值得注意的是,虽然 Solidity 不允许修饰符本身被重载[^2] ,但是它们仍然能与带有 `virtual` 属性的函数一起工作得很好。这意味着可以在不影响原有逻辑的前提下调整执行流程控制策略。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值