备注

  • 本文绝大部分是直接从 搭建僵尸工厂 的一个以闯关学习Solidity相关知识的(国外?)网站抄写下来的,该网站自带sodility编辑器,而且每章节都必须按照实战演习的内容完成测试才能进入到下一章节,非常适合用一定编程基础的小伙伴自学solidity编程
  • 我整理这篇文章,一是分享觉得好的solidity学习资源给大伙;二是重新学习下solidity;三是整理上述网站的学习内容,让我自己找起来方便;
  • 上述网站是开源的,如本篇内容有侵权,可联系本博客删除;
  • 好记性不如烂笔头,抄一遍等于过一遍脑子,比扫一遍或看一遍的效果好的多得多;
  • 最后demo的步骤序号与标题序号一致,如果哪个步骤忘了具体含义,可查看对应序号的标题内容;

1. 合约

  • 所有Solidity源码必须冠以version pragrma 标明Solidity编译器的版本,以避免将来新的编译器可能破坏你的代码:
  • Solidity中合约的含义就是一组代码(它的函数)和数据(它的状态) ,它们位于以太坊区块链的一个特定地址上。

2. 状态变量和整数

  • 状态变量 是永久地保存在合约中;

无符号整数:uint

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

注:Solidity中,uint实际上是uint256代名词,一个256位的无符号整数;你也可以定义位数少的uints—uint8,uint16,uint32等···

3. 数学运算

  • 加法: x + y
  • 减法: x - y
  • 乘法: x * y
  • 除法: x / y
  • 取模/求余: x % y
  • 乘方: x ** y (例子:5 ** 2=25)

4. 结构体

  • 有时你需要更复杂的数据类型,Solidity提供了结构体;结构体允许你生成一个更复杂的数据类型,它有多个属性
struct Person {uint age;string name;
}

注: string类型:字符串用于保存任意长度的UFT-8编码数据。

5. 数组

  • Solidity支持两种数据:静态数组和动态数组:
//固定长度为2的静态数组;
uint[2] fixedArray;
//固定长度为5的string类型的静态数组
string[5] stringArray;
//动态数组,长度不固定,可以动态添加元素
uint[] dynamicArry;

5.1 公共数组

  • 你可以定义public数组,Solidity会自动创建getter方法,语法如下:
Person[] public perple;

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

6. 定义函数

  • 在Solidity中函数定义的语法如下:
function eatHamburgers(string _name, uint _amount) {
}

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

注:习惯上函数里的变量都是以(_)开头(但不是硬性规定)以区别全局变量。

7. 使用结构体和数组

现在我们学习创建新的Person结构,然后把它加入到people的数组中:

//创建一个新的Person
Person satoshi = Person(172,"satoshi");
//将新创建的satoshi添加进people数组
people.push(satoshi);

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

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

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

8. 私有/公共函数

  • Solidity定义的函数的属性默认为公共,这意味着任何一方(或其他合约)都可以调用你合约里的函数
    显然,不是什么时候都需要这样,而且这样的合约易于受到攻击,所以将自己的函数定义为私有是一个好的编程习惯,只有当你需要外部世界调用它时才将它设置为公共
    如何定义一个私有的函数呢?
uint[] numbers;
function _addToArray(uint _number) private {numbers.push(_number);
}

这意味着只有我们合约中的其他函数才能够调用这个函数,给numbers数组添加新成员;
可以看到,在函数名字后面使用关键字private即可 和函数的参数类似,私有函数的名字用(_)起始;

9. 函数的更多属性

返回值

要想函数返回一个数值,按如下定义:

string greeting = "What's up dog";function syHello() public resutns(string) {return greeting;
}

Solidity里,函数的定义里可包含返回值的数据类型

函数的修饰符

上面的函数实际上没有改变Solidity里的状态,它没有改变任何值或者写任何东西;
这种情况下我们可以把函数定义为view—意味着它只能读取数据而不能更改数据

functioin sayHello() public view returns (string) {}

Solidity还支持pure函数—表明这个函数甚至都不访问应用里的函数 ,例如:

functioin _multply(uint a,uint b) private pure returns(uint) {return a * b;
}

这个函数甚至都不读取应用里的状态—它的返回值完全取决于它的输入参数,在这种情况下我们把函数定义为pure

注:可能很难记住何时把函数标记为pure/view;幸运的是,Solidity编辑器会给出提示,提醒你使用这些修饰符。

10.Keccak256 和 类型转换

Ethereum内部有一个散列函数keccak256 ,它用了SHA3版本;一个散列函数基本上就是把一个字符串转换为一个256位的16进制数字。 字符串的一个微小变化会引起散列数据极大变化。
这在Ethereum中有很多应用,但是我们现在知识用它造一个伪随机数;

//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");

显而易见,输入字符串只改变了一个字母,输出就已经天壤之别了。

注:在区块链中安全地生产一个随机数是一个很难的问题,本例的方法不安全;

类型转换

uint8 a = 5;
uint b = 6;
//将会抛出错误,因为a*b返回uint,而不是uint8
uint8 c = a * b;
//我们需要将b转换为uint8
uint8 c = a * uint8(b);

上面, a * b 返回类型是 uint, 但是当我们尝试用 uint8 类型接收时, 就会造成潜在的错误。如果把它的数据类型转换为 uint8, 就可以了,编译器也不会出错。

12. 事件

事件是合约和区块链通讯的一种机制。你的前端应用“监听”某些事件,并做出反应;

//这里建立事件
event IntegersAdded(uint x, uint y, uint result);function add(uint _x, uint _y) public {uint result = _x + _y;//触发事件,通知appIntegersAdded(_x,_y,result);return result;
}

你的app前端可以监听这个事件,JavaScript实现如下:

YourContract.IntegersAdded(function(error,result){
})

demo

pragma solidity ^0.4.19;  //  1.1这里写版本指令//1.2 这里建立智能合约
contract ZombieFactory {//12.1  定义一个 事件 叫做 NewZombie。 它有3个参数: zombieId (uint), name (string), 和 dna (uint)。event NewZombie(uint zombieId, string name, uint dna);//2. 定义 dnaDigits 为 uint 数据类型, 并赋值 16。uint dnaDigits = 16;// 3. 建立一个uint类型的变量,名字叫dnaModulus, 令其等于 10 的 dnaDigits 次方.uint dnaModulus = 10 ** dnaDigits;//4.1 建立一个struct 命名为 Zombie.//4.2 Zombie 结构体有两个属性: name (类型为 string), 和 dna (类型为 uint)。struct Zombie {string name;uint dna;}//5. 创建一个数据类型为 Zombie 的结构体数组,用 public 修饰,命名为:zombies.Zombie[] public zombies;//   //6. 建立一个函数 createZombie。 它有两个参数: _name (类型为string), 和 _dna (类型为uint)。
//  function createZombie(string _name, uint _dna) {
//      //7 在函数体里新创建一个 Zombie, 然后把它加入 zombies 数组中。 新创建的僵尸的 name 和 //dna,来自于函数的参数。(用一行代码简洁地完成它。)
//      zombies.push(Zombie(_name,_dna));
//  }//8. 我们合约的函数 createZombie 的默认属性是公共的,这意味着任何一方都可以调用它去创建一个僵尸。 变 createZombie 为私有函数,不要忘记遵守命名的规矩哦function _createZombie(string _name, uint _dna) private {//7 在函数体里新创建一个 Zombie, 然后把它加入 zombies 数组中。 新创建的僵尸的 name 和 dna,来自于函数的参数。(用一行代码简洁地完成它。)//zombies.push(Zombie(_name,_dna));//12.2  需要定义僵尸id。 array.push() 返回数组的长度类型是uint - 因为数组的第一个元素的索引是 0, array.push() - 1 将是我们加入的僵尸的索引。 zombies.push() - 1 就是 id,数据类型是 uint。在下一行中你可以把它用到 NewZombie 事件中。//12.3 修改 _createZombie 函数使得当新僵尸造出来并加入 zombies数组后,生成事件NewZombie。uint id = zombies.push(Zombie(_name, _dna)) - 1;NewZombie(id, _name, _dna);}//9.1 创建一个 private 函数,命名为 _generateRandomDna。它只接收一个输入变量 _str (类型 string), 返回一个 uint 类型的数值。//9.2 此函数只读取我们合约中的一些变量,所以标记为view。function _generateRandomDna(string _str) private view returns(uint) {//10.1  第一行代码取 _str 的 keccak256 散列值生成一个伪随机十六进制数,类型转换为 uint, 最后保存在类型为 uint 名为 rand 的变量中。//10.2 我们只想让我们的DNA的长度为16位 (还记得 dnaModulus?)。所以第二行代码应该 return 上面计算的数值对 dnaModulus 求余数(%)。uint rand = uint(keccak256(_str));return rand % dnaModulus;}//11.1 创建一个 public 函数,命名为 createRandomZombie. 它将被传入一个变量 _name (数据类型是 string)。 (注: 定义公共函数 public 和定义一个私有 private 函数的做法一样)。function createRandomZombie(string _name) public {//11.2 函数的第一行应该调用 _generateRandomDna 函数,传入 _name 参数, 结果保存在一个类型为 uint 的变量里,命名为 randDna。uint randDna = _generateRandomDna(_name);//11.3 第二行调用 _createZombie 函数, 传入参数: _name 和 randDna。_createZombie(_name,randDna);}
}

【Solidity学练系列1---搭建僵尸工厂】相关推荐

  1. 一起学WPF系列(2):第一个WPF应用程序

    概述 Windows Presentation Foundation (WPF) 是下一代显示系统,用于生成能带给用户震撼视觉体验的 Windows 客户端应用程序.使用 WPF,您可以创建广泛的独立 ...

  2. 从源代码学Python系列目录

    Hello,我是 Alex 007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫 Alex 的人太多了,再加上每天007的生活,Alex 007就诞生了. 从源代码学Python系列 第 ...

  3. 从零学ELK系列(一):为什么要跟我学从零学ELK系列

    [前言] 网上写ELK日志收集系统,项目集成ELK,Docker,本地安装虚拟机这些孤立技术点文章汗牛充栋:但是很少有文章能即生动又能结合场景的从零一步一步搭建一套生产级日志收集系统并将生产项目集成日 ...

  4. 高效便捷组卷功能,学练考一体化让考试更轻松

    在线考试系统是很多企业甚至企事业单位想要搭建的平台,无论是平时内部考试考核还是定期的员工培训都需要用到线上考试系统.尤其现在线上考试系统和培训功能挂钩,学练考一体化平台对于使用者来说是更加方便的. 而 ...

  5. 神经网络学习小记录50——Pytorch 利用efficientnet系列模型搭建yolov3目标检测平台

    神经网络学习小记录50--Pytorch 利用efficientnet系列模型搭建yolov3目标检测平台 学习前言 什么是EfficientNet模型 源码下载 EfficientNet模型的实现思 ...

  6. 轻松学Linux系列课程-赵永刚-专题视频课程

    轻松学Linux系列课程-4263人已学习 课程介绍         从0开始,Linux云计算系列课程,包含Linux初级运维.运维.初级架构师.云计算运维及开发..... 课程收益      讲师 ...

  7. 神经网络学习小记录26——Keras 利用efficientnet系列模型搭建yolov3目标检测平台

    神经网络学习小记录26--Keras 利用efficientnet系列模型搭建efficientnet-yolov3目标检测平台 学习前言 什么是EfficientNet模型 源码下载 Efficie ...

  8. 重学网络系列之(Ping与网关)

    前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好的时间是十年前,其次是现在 叨絮 网关,路由,其 ...

  9. 中秋佳节速成C语言_老九零基础学编程系列之C语言【章节1-章节5】

    前言 现在是北京时间2019.09.13 11:16 今天是月饼节啊!祝大家月饼节快乐~ 然而~作为一个本科来自生科院的工科女 为了当C语言助教 只能? 值此佳节,凿壁偷光/勤学苦练/悬梁刺骨/孙康映 ...

最新文章

  1. Windows Embedded Standard开发初体验(四)
  2. 微信协议简单调研笔记
  3. SQL优化常用方法24
  4. cocos2d-x的A*寻路
  5. 北京大力度建设城市绿道,我们身边处处是风景
  6. 配电技术——配电线路系统电气设备详解
  7. Eclipse 打开文件出现乱码情况总结
  8. MySQL常用权限的解释
  9. Sql语句中IN和exists的区别及应用
  10. HttpClient调用http接口(POST)
  11. Mysql-5.5+Heartbeat-3.0.5+DRBD
  12. c语言编程软件支持win8,C语言编程软件vc6.0(支持win7 / win8 / 10)官方免费版6.0
  13. 一切皆是文件:UNIX,Linux 操作系統的設計哲學
  14. bugku misc disordered_zip
  15. HDU-4826(DP动态)
  16. pandas DatetimeIndex indexing
  17. 基于 Selenium 掘金自动签到、抽奖的定时任务
  18. 浅识WebGL和Three.js
  19. 原子性 可见性 有序性_极简主义的内容可见性
  20. python获取网站代码_python爬虫1——获取网站源代码(豆瓣图书top250信息)

热门文章

  1. Go语言入门——环境准备篇(一)
  2. Java企业信息化系统,开源OA openSource OA Platform 本地搭建运行。
  3. 最快1天搭建短视频APP!阿里云短视频解决方案上线
  4. 【微信小程序】wxs如何调试?
  5. 宽容还是忍让,软弱还是大度
  6. javaGUI编写的键盘检测,利用GUI实现按键效果展示
  7. 「推荐」Linux远程连接工具之ssh客户端工具
  8. 最全最详细-线性规划(最小二乘、正交回归、梯度下降、仿真)
  9. 吴恩达ChatGPT网课笔记Prompt Engineering——训练ChatGPT前请先训练自己
  10. 一个Ubuntu下禁用笔记本键盘触摸板的简单脚本