尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Solidity 语言设计溯源:来自 C++、JavaScript 与 Python 的影响

Solidity 语言设计溯源:来自 C++、JavaScript 与 Python 的影响 Solidity 语言设计溯源来自 C、JavaScript 与 Python 的影响【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity导读Solidity 是一门面向以太坊智能合约的静态类型编程语言其语法与语义并非凭空诞生而是从 C、JavaScript、Python 等成熟语言中借鉴与演化而来。本文以官方文档 docs/language-influences.rst 为骨架系统梳理 Solidity 从三种语言继承的核心设计C 带来的语法与类型系统、JavaScript 的历史痕迹及其在 0.4.0 之后的逐步退场、Python 贡献的修饰符modifier、多重继承与 C3 线性化。读完本文你将理解 Solidity 中众多似曾相识的语法背后的设计动机并能在编写合约时更准确地把握继承顺序、super调用与类型转换的行为。一、总览一门花括号语言的基因图谱Solidity 在官方文档中被明确归类为花括号语言curly-bracket language即使用{}界定代码块的语法族。在这个家族中它最深刻地受到 C 的影响同时从 Python 与 JavaScript 中借用了一部分高层概念。三个语言的影响叠加最终形成了今天 Solidity 的独特面貌影响来源核心贡献当前状态C变量声明、for 循环、函数重载、类型转换、静态类型体系持续存在构成语法主干JavaScript函数级作用域、var关键字、function关键字、import 语法自 0.4.0 起大幅弱化仅保留少量痕迹Pythonmodifier模仿装饰器、多重继承、C3 线性化、super、赋值/拷贝语义持续存在构成继承与语义模型需要注意的是文档所描述的语言影响属于设计层面的渊源与编译器的具体实现是两个层面前者回答语法为什么长这样后者回答编译器如何把语法变成 EVM 字节码。本文在介绍渊源的同时也会结合仓库源码说明对应机制的落地位置。二、C塑造语法主干的最大影响源文档明确指出Solidity 受 C 的影响最为深远这种影响直接体现在日常写合约时最常用的语法元素上变量声明uint256 x 1;这种类型在前、名字在后的声明方式与 C/C 一致与 Go、Rust 等名字在前的语言形成对比。for 循环for (uint256 i 0; i n; i)的三段式结构完全沿袭 C 家族包括初始化、条件、迭代表达式三个部分。函数重载overloading允许在同一合约中定义多个同名函数只要参数类型或数量不同即可区分。这与 C 的重载规则一脉相承。隐式与显式类型转换Solidity 支持在兼容类型之间的隐式转换如从uint8提升到uint16也支持通过显式转换语法uint8(x)进行窄化转换。这套隐式宽化、显式窄化的规则设计明显带有 C 类型系统的影子。从当前仓库源码看类型转换的完整规则集中在 libsolidity/ast/Types.cpp 中实现函数重载的分辨逻辑则由 libsolidity/analysis/TypeChecker.cpp 负责。可以说C 的影响不仅停留在语法表面也渗透进了编译器的类型检查管线。此外C 的影响还体现在更底层的细节上Solidity 的整数类型uint8到uint256、int8到int256与 C 的固定宽度整数类型在思路上同源只是受 EVM 256 位字长的约束做了扩展。花括号作用域、else if分支链、三目运算符等语法细节也都直接继承自 C 家族。三、JavaScript从深度借鉴到仅存痕迹3.1 历史渊源与 0.4.0 的转折文档揭示了 Solidity 的一段重要历史在语言早期Solidity 曾部分受 JavaScript 影响具体体现在两点函数级作用域function-level scoping变量在整个函数体内可见而非像现代语言那样局限于声明所在的代码块var关键字用var声明变量由编译器推断类型。从 0.4.0 版本开始官方有意识地削减了 JavaScript 的影响。这一决策在仓库的版本迁移文档中留下了明确的证据docs/050-breaking-changes.rst 记载Thevarkeyword is now disallowed to favor explicitness.var关键字现已被禁止以提倡显式性并在示例代码中展示了旧版本中var z someInteger();的写法docs/070-breaking-changes.rst 进一步确认The keywordvarcannot be used anymore.var关键字已不可再使用。也就是说var在 0.5.0 中被正式禁用到 0.7.0 后彻底从语言中消失今天写合约必须为每个变量显式声明类型。3.2 今天留下的两大痕迹文档指出当前 Solidity 与 JavaScript 的主要相似点仅剩两处function关键字定义函数时使用function例如function transfer(address to, uint256 amount) public。这与 JavaScript 的函数声明语法在关键字层面一致但语义完全不同——Solidity 的函数有可见性public/private/internal/external和状态可变性view/pure/payable修饰属于编译期静态检查而 JavaScript 的函数是动态的。import 语法与语义Solidity 支持import ./other.sol;、import {A, B} from ./lib.sol;等形式命名导入、别名导入as等写法与 ES Module 高度相似。具体的解析与导入重映射逻辑可以在 libsolidity/interface/ImportRemapper.cpp 与 libsolidity/interface/FileReader.cpp 中看到。除了这两点之外Solidity 已经回归到与其他花括号语言基本一致的形态不再保有显著的 JavaScript 影响。文档对此的总结很直白Besides those points, Solidity looks like most other curly-bracket languages and has no major JavaScript influence anymore.四、Python修饰符、继承与语义模型如果说 C 提供了 Solidity 的骨架Python 则提供了相当一部分血肉——尤其是合约的组织与复用机制。文档明确列出的 Python 影响包括以下四点。4.1 Modifier以更受限的方式模仿装饰器Solidity 的修饰符modifier是在尝试以功能大幅受限的方式模仿 Python 的装饰器decorator。Python 装饰器通过decorator语法包裹函数可以在函数执行前后注入逻辑Solidity 的 modifier 则在函数声明时追加onlyOwner之类的修饰符并在函数体中以_占位符标记原始函数体的插入点// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.0 0.9.0; contract Owned { address public owner; constructor() { owner msg.sender; } modifier onlyOwner() { require(msg.sender owner, Not the owner); _; // 原始函数体在此处执行 } function changeOwner(address newOwner) public onlyOwner { owner newOwner; } }对比 Pythondef only_owner(func): def wrapper(*args, **kwargs): if args[0].owner ! ...: raise PermissionError return func(*args, **kwargs) return wrapper class Owned: only_owner def change_owner(self, new_owner): ...两者的共同点是在函数定义处声明横切逻辑区别在于 Python 装饰器是运行时的动态包装可以任意组合与反射而 Solidity 的 modifier 是编译期展开的静态机制功能刻意保持简单。modifier 的解析与展开发生在 libsolidity/analysis/ContractLevelChecker.cpp 等分析阶段最终在代码生成阶段被内联进函数体。4.2 多重继承与 C3 线性化Python 是少数原生支持多重继承的主流语言Sol 引入 C3 线性化C3 Linearization来消除菱形继承的歧义。C3 线性化算法最早由 Python 2.3 引入用于决定 MRO方法解析顺序。在编译器中落地仓库源码 libsolidity/analysis/NameAndTypeResolver.h 明确写着Computes C3-Linearization of base contracts其实现位于 libsolidity/analysis/NameAndTypeResolver.cpp 的linearizeBaseContracts函数中核心的 C3 合并算法由cThreeMerge实现同文件第 449 行起。算法要点包括输入是按从派生到基类顺序排列的基类列表的列表候选契约必须仅出现在各列表头部appearsOnlyAtHead见 NameAndTypeResolver.cpp合并失败时返回空列表进而触发编译错误Linearization of inheritance graph impossible错误码 5005。在语言文档中的解释docs/contracts/inheritance.rst 的 Multiple Inheritance and Linearization 一节详细说明了这一机制并给出一个典型的不合法示例// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.0 0.9.0; contract X {} contract A is X {} // 这将无法编译 contract C is A, X {}原因正如文档所述C要求X覆盖A因为按A, X的顺序列出而A本身又要求覆盖X形成无法化解的矛盾。从源码结构看这正是cThreeMerge找不到仅出现在头部的候选者时返回空列表的场景。一个与 Python 的重要差异值得注意基类在is指令中的排列顺序是反过来的——Solidity 要求按最基类化到最派生排列而 Python 正好相反。搜索时 Solidity 从右往左进行深度优先查找Python 是从左往右且已搜索过的基类会被跳过。4.3super关键字super同样取自 Python。在多重继承中super用于沿线性化顺序调用下一个基类的同名函数而不是直接指定某个具体基类。这在钻石继承场景中尤为关键——它保证了每个基类函数在整条继承链中只被调用一次。Solidity 的super在编译器中体现为一种特殊的合约类型。在 libsolidity/ast/Types.cpp 中可以看到类型名为t_super的表示而 docs/contracts/inheritance.rst 中的示例表明Final合约调用super时实际执行的是线性化顺序中的下一个实现并且super调用使用 JUMP 而非消息调用见该文档第 26 行因此成本更低。super的语义实现依赖linearizedBaseContracts中存储的线性化顺序这正是上一小节 C3 算法的直接产出。4.4 值类型与引用类型的赋值/拷贝语义文档提到的第四项 Python 影响是值类型和引用类型的一般赋值与拷贝语义。这一点的通俗理解是值类型如uint、bool、address在赋值与传参时按值拷贝修改副本不影响原变量引用类型如array、struct、mapping则根据存储位置storage/memory/calldata的不同表现出引用共享或拷贝的语义差异。这种值类型天然拷贝、引用类型需显式声明数据位置的模型与 Python 中不可变对象按值语义、可变对象按引用语义的心智模型相通。Solidity 的具体规则例如storage赋值是引用、memory之间赋值是拷贝在 docs/types/reference-types.rst 中有完整阐述编译器侧的实现则在 libsolidity/codegen/CompilerUtils.cpp 与 libsolidity/codegen/ArrayUtils.cpp 中。五、对合约开发者的实践启示理解了三种语言的基因图谱后可以在日常开发中做出更符合语言设计意图的选择显式胜过隐式既然var因提倡显式性而被移除就应始终为变量写出完整类型避免依赖类型推断带来的可读性损失。掌握继承顺序规则在is指令中必须按最基类化到最派生排列直接基类一旦写出contract C is A, X {}其中A is X这样的矛盾继承图编译器会直接报 Linearization of inheritance graph impossible。可以用contract C is X, A之类顺序修复。善用super而非硬编码基类名在多重继承链中super.f()会沿线性化顺序找到下一个实现语义上比BaseName.f()更稳健且super调用走 JUMP 而非消息调用Gas 成本更低。区分拷贝与引用赋值storage结构体给另一个storage变量是引用共享修改会互相影响复制到memory才是真正的拷贝。在函数参数传递时注意memory/calldata的选择这直接关系到 Gas 消耗与数据安全。六、总结Solidity 是一门站在巨人肩膀上的语言C 提供了类型系统、控制流与重载等语法主干JavaScript 的影响在 0.4.0 之后被系统性地削减仅保留function与 import 语法Python 则贡献了修饰符以更受限的 modifier 形式、C3 线性化多重继承、super与拷贝语义模型。官方文档 docs/language-influences.rst 是这一结论的第一手来源而本仓库的编译器源码尤其是 libsolidity/analysis/NameAndTypeResolver.cpp 中的 C3 实现、libsolidity/ast/Types.cpp 中的类型系统则为这些渊源提供了工程层面的印证。理解这些设计选择不仅能解释 Solidity 语法为什么长这样也能帮助你在面对继承、重载与类型转换时做出更正确的合约设计决策。【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表