扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
当您对外部模块的存储库进行了 fork (例如修复模块代码中的问题或添加功能)时,您可以让 Go 工具将您的 fork 用于模块的源代码。这对于测试您自己的代码的更改很有用。
企业建站必须是能够以充分展现企业形象为主要目的,是企业文化与产品对外扩展宣传的重要窗口,一个合格的网站不仅仅能为公司带来巨大的互联网上的收集和信息发布平台,成都创新互联面向各种领域:成都OPP胶袋等成都网站设计公司、全网营销推广解决方案、网站设计等建站排名服务。
为此,您可以使用go.mod 文件中的replace指令将外部模块的原始模块路径替换为存储库中 fork 的路径。这指示 Go 工具在编译时使用替换路径(fork 的位置),例如,同时允许您保留import 原始模块路径中的语句不变。
在以下 go.mod 文件示例中,当前模块需要外部模块example.com/theirmodule。然后该replace指令将原始模块路径替换为example.com/myfork/theirmodule模块自己的存储库的分支。
设置require/replace对时,使用 Go 工具命令确保文件描述的需求保持一致。使用go list命令获取当前模块正在使用的版本。然后使用go mod edit命令将需要的模块替换为fork:
注意: 当您使用该replace指令时,Go 工具不会像添加依赖项中所述对外部模块进行身份验证。
您可以使用go get命令从其存储库中的特定提交为模块添加未发布的代码。
为此,您使用go get命令,用符号@指定您想要的代码 。当您使用go get时,该命令将向您的 go.mod 文件添加一个 需要外部模块的require指令,使用基于有关提交的详细信息的伪版本号。
以下示例提供了一些说明。这些基于源位于 git 存储库中的模块。
当您的代码不再使用模块中的任何包时,您可以停止将该模块作为依赖项进行跟踪。
要停止跟踪所有未使用的模块,请运行go mod tidy 命令。此命令还可能添加在模块中构建包所需的缺失依赖项。
要删除特定依赖项,请使用go get,指定模块的模块路径并附加 @none,如下例所示:
go get命令还将降级或删除依赖于已删除模块的其他依赖项。
当您使用 Go 工具处理模块时,这些工具默认从 proxy.golang.org(一个公共的 Google 运行的模块镜像)或直接从模块的存储库下载模块。您可以指定 Go 工具应该使用另一个代理服务器来下载和验证模块。
如果您(或您的团队)已经设置或选择了您想要使用的不同模块代理服务器,您可能想要这样做。例如,有些人设置了模块代理服务器,以便更好地控制依赖项的使用方式。
要为 Go 工具指定另一个模块代理服务器,请将GOPROXY 环境变量设置为一个或多个服务器的 URL。Go 工具将按照您指定的顺序尝试每个 URL。默认情况下,GOPROXY首先指定一个公共的 Google 运行模块代理,然后从模块的存储库直接下载(在其模块路径中指定):
您可以将变量设置为其他模块代理服务器的 URL,用逗号或管道分隔 URL。
Go 模块经常在公共互联网上不可用的版本控制服务器和模块代理上开发和分发。您可以设置 GOPRIVATE环境变量。您可以设置GOPRIVATE环境变量来配置go命令以从私有源下载和构建模块。然后 go 命令可以从私有源下载和构建模块。
GOPRIVATE或环境变量可以设置为匹配模块前缀的全局模式列表,这些GONOPROXY前缀是私有的,不应从任何代理请求。例如:
本教程介绍了使用 Godatabase/sql及其标准库中的包访问关系数据库的基础知识。
您将使用的database/sql包包括用于连接数据库、执行事务、取消正在进行的操作等的类型和函数。
在本教程中,您将创建一个数据库,然后编写代码来访问该数据库。您的示例项目将是有关老式爵士乐唱片的数据存储库。
首先,为您要编写的代码创建一个文件夹。
1、打开命令提示符并切换到您的主目录。
在 Linux 或 Mac 上:
在 Windows 上:
2、在命令提示符下,为您的代码创建一个名为 data-access 的目录。
3、创建一个模块,您可以在其中管理将在本教程中添加的依赖项。
运行go mod init命令,为其提供新代码的模块路径。
此命令创建一个 go.mod 文件,您添加的依赖项将在其中列出以供跟踪。
注意: 在实际开发中,您会指定一个更符合您自己需求的模块路径。有关更多信息,请参阅一下文章。
GO语言(二十五):管理依赖项(上)
GO语言(二十六):管理依赖项(中)
GO语言(二十七):管理依赖项(下)
接下来,您将创建一个数据库。
在此步骤中,您将创建要使用的数据库。您将使用 DBMS 本身的 CLI 创建数据库和表,以及添加数据。
您将创建一个数据库,其中包含有关黑胶唱片上的老式爵士乐录音的数据。
这里的代码使用MySQL CLI,但大多数 DBMS 都有自己的 CLI,具有类似的功能。
1、打开一个新的命令提示符。
在命令行,登录到您的 DBMS,如下面的 MySQL 示例所示。
2、在mysql命令提示符下,创建一个数据库。
3、切到您刚刚创建的数据库,以便您可以添加表。
4、在文本编辑器的 data-access 文件夹中,创建一个名为 create-tables.sql 的文件来保存用于添加表的 SQL 脚本。
将以下 SQL 代码粘贴到文件中,然后保存文件。
在此 SQL 代码中:
(1)删除名为album表。 首先执行此命令可以让您更轻松地稍后重新运行脚本。
(2)创建一个album包含四列的表:title、artist和price。每行的id值由 DBMS 自动创建。
(3)添加带有值的四行。
5、在mysql命令提示符下,运行您刚刚创建的脚本。
您将使用以下形式的source命令:
6、在 DBMS 命令提示符处,使用SELECT语句来验证您是否已成功创建包含数据的表。
接下来,您将编写一些 Go 代码进行连接,以便进行查询。
现在你已经有了一个包含一些数据的数据库,开始你的 Go 代码。
找到并导入一个数据库驱动程序,该驱动程序会将您通过database/sql包中的函数发出的请求转换为数据库可以理解的请求。
1、在您的浏览器中,访问SQLDrivers wiki 页面以识别您可以使用的驱动程序。
2、使用页面上的列表来识别您将使用的驱动程序。为了在本教程中访问 MySQL,您将使用 Go-MySQL-Driver。
3、请注意驱动程序的包名称 - 此处为github.com/go-sql-driver/mysql.
4、使用您的文本编辑器,创建一个用于编写 Go 代码的文件,并将该文件作为 main.go 保存在您之前创建的数据访问目录中。
5、进入main.go,粘贴以下代码导入驱动包。
在此代码中:
(1)将您的代码添加到main包中,以便您可以独立执行它。
(2)导入 MySQL 驱动程序github.com/go-sql-driver/mysql。
导入驱动程序后,您将开始编写代码以访问数据库。
现在编写一些 Go 代码,让您使用数据库句柄访问数据库。
您将使用指向结构的指针sql.DB,它表示对特定数据库的访问。
编写代码
1、进入 main.go,在import您刚刚添加的代码下方,粘贴以下 Go 代码以创建数据库句柄。
在此代码中:
(3)使用 MySQL 驱动程序Config和FormatDSN类型以收集连接属性并将它们格式化为连接字符串的 DSN。
该Config结构使代码比连接字符串更容易阅读。
(4)调用sql.Open 初始化db变量,传递 FormatDSN。
(5)检查来自 的错误sql.Open。例如,如果您的数据库连接细节格式不正确,它可能会失败。
为了简化代码,您调用log.Fatal结束执行并将错误打印到控制台。在生产代码中,您会希望以更优雅的方式处理错误。
(6)调用DB.Ping以确认连接到数据库有效。在运行时, sql.Open可能不会立即连接,具体取决于驱动程序。您在Ping此处使用以确认 database/sql包可以在需要时连接。
(7)检查来自Ping的错误,以防连接失败。
(8)Ping如果连接成功,则打印一条消息。
文件的顶部现在应该如下所示:
3、保存 main.go。
1、开始跟踪 MySQL 驱动程序模块作为依赖项。
使用go get 添加 github.com/go-sql-driver/mysql 模块作为您自己模块的依赖项。使用点参数表示“获取当前目录中代码的依赖项”。
2、在命令提示符下,设置Go 程序使用的DBUSER和DBPASS环境变量。
在 Linux 或 Mac 上:
在 Windows 上:
3、在包含 main.go 的目录中的命令行中,通过键入go run来运行代码。
连接成功了!
接下来,您将查询一些数据。
1、下载go的zip文件。并且一定要把文件解压到c:\go目录下。
2、配置windows的高级环境变量。包括:GOROOT、GOOS、GOBIN、GOARCH。并且在path变量里面把c:\go\bin加入。以便可以在命令行直接运行go命令。
举例:我的机器:
GOPATH= c:\go;c:\go\src;F:\workspace\goSample01;
GOBIN=c:\go\bin;F:\workspace\goSample01\bin;
其中,c:\go是go的安装路径;
F:\workspace\goSample01是我写的go语言项目的工程目录;
F:\workspace\goSample01\bin是go语言项目的工程目录下的可执行文件路径;
3、在完成环境变量配置后,打开一个命令行窗口,直接输入go,然后回车,看看是否出现go的帮助信息。如果出现,那么go的基本环境就OK了。
注意:这个基本环境不包含开发工具,也不能直接编译带C代码的go程序。
4、
(可选)为了支持Import远程包,最好装个gomingw。下载地址:
/downloads/list。如果下的是压缩包,请把它解压到C盘。例如,C:\gowin-env。里面有个Console.bat是以后使用go
get的环境。举例:有个文件a.go,里面import(
"fmt"
"github.com/astaxie/beedb"
_ "github.com/ziutek/mymysql/godrv"
为了编译该a.go文件,需要启动Console.bat,然后在该命令行窗口,进入c:\go\src目录下,执行go getgithub.com/astaxie/beedb
Go get github.com/ziutek/mymysql/godrv .
Go会自动下载该远程包并编译和安装这些包。
配置goclipse(可选)
(如果不喜欢eclipse开发工具,请跳过这个配置。)
1、下载并安装goclipse插件。Goclipse是go语言for eclipse的插件,下载地址:
2、启动eclipse并创建go项目。然后写个最简单的helloworld.go文件,并运行。代码如下:
packagemainimport"fmt"func main(){ fmt.Printf("hello, world")}
配置gocode(可选)
如果不需要go语法辅助和eclipse里面的(按ALT+/)弹出go语言自动辅助功能,请跳过这个配置。
1、下载gocode的zip文件,解压后放在go的bin目录下。
2、下载并安装Git软件。并且在path里面配置git的执行路径。例如c:\git\bin
3、在命令行执行:go build .\gocode。如果一切正常,那么将会编译生成一个gocode.exe文件在go的bin目录下。如果编译失败,那么就转第4步。
4、如果第3步直接编译gocode源文件成功,那就直接到第5步。否则,就需要通过git下载gocode源文件,然后再编译。在命令行执行:go get -u github.com/nsf/gocode 。就会生成gocode.exe文件。
5、在goclipse插件里面指定gocode的路径。就可以在elcipse里面调用gocode来帮助写编码了。
从开发工具这块看,go语言还不够成熟,开发工具都还不完善,有待改进。
下载go-tour教程源代码(可选)
Google有个在线运行go语言的教程(),很不错。支持在web上直接运行大部分的go程序,想了解这个教程的源代码的朋友可以通过以下方式获取。如果没兴趣,可以跳过这个步骤。
1、下载安装Mercurial软件。
2、在命令行下输入:
hg clone
作为测试用的。如果把http改成https协议,下载就会失败。搞不懂。
编译带调用C代码的go文件(可选)
1、为了在windows下编译带C代码的go程序,你首先需要下载并安装MinGW或者Cygwin。
2、首选安装MinGW。在安装MinGW之后,记得要把MinGW安装目录\bin路径设置在path环境变量里面,以便能在dos窗口下直接调用gcc。
3、下载一个gowin-env。下载地址:gowin-env。下载后解压到某个目录下,例如:C:\gowin-env. 然后,编辑go-env.bat。配置相关的go参数。例如,我的配置是:
set GOARCH=386
set GOOS=windows
set GOROOT=c:\go
set GOBIN=%GOROOT%\bin
set GOPATH=%GOROOT%;F:\workspace\goSample01;
设置好go-env.bat后,就可以点击Console.bat来启动编译和运行窗口。
4、编写一个带C代码的go程序。例如,testc.go
5、编译
例如:
go build -compiler gccgo test_c.go
运行调用C代码的go文件(可选)
1、testc.go.
创建rand目录,然后在rand里面创建testc.go. 代码如下:
package rand
/*
//
#include stdio.h
*/
import "C"
func PrintHello() {
C.puts(C.CString("Hello, world\n"))
}
2、a.go
在rand下创建a.go.代码如下:
package rand
import "fmt"
func SayHello(name string){
fmt.Println(name)
}
3、test_import.go
在rand的上一级创建test_import.go。代码如下:
package main
import "./rand"
func main(){
rand.SayHello("tom")
rand.PrintHello()
}
4、运行test_import.go
go run test_import.go
在测试其它几个C代码的时候,发现windows版本的cgo还有些编译问题,同样的代码转移到苹果的XCODE下就没有问题。后来终于发现原因了,原来有些例子是unix平台下的,而在windows平台下,方法名和参数需要做调整。
例如:下面代码在windows下编译报一堆错误。
package rand
/*
#include stdlib.h
*/
import "C"
func Random() int {
return int(C.random())
}
func Seed(i int) {
C.srandom(C.uint(i))
}
这里需要把return int(C.random()) 修改为“return int(C.rand())”
C.srandom(C.uint(i))修改为“C.srand(C.uint(i))”编译就OK了。
package main
import (
"fmt"
"net"
"os"
)
func main() {
addrs, err := net.InterfaceAddrs()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, address := range addrs {
// 检查ip地址判断是否回环地址
if ipnet, ok := address.(*net.IPNet); ok !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
fmt.Println(ipnet.IP.String())
}
}
}
}
智能合约调用是实现一个 DApp 的关键,一个完整的 DApp 包括前端、后端、智能合约及区块 链系统,智能合约的调用是连接区块链与前后端的关键。
我们先来了解一下智能合约调用的基础原理。智能合约运行在以太坊节点的 EVM 中。因此要 想调用合约必须要访问某个节点。
以后端程序为例,后端服务若想连接节点有两种可能,一种是双 方在同一主机,此时后端连接节点可以采用 本地 IPC(Inter-Process Communication,进 程间通信)机制,也可以采用 RPC(Remote Procedure Call,远程过程调用)机制;另 一种情况是双方不在同一台主机,此时只能采用 RPC 机制进行通信。
提到 RPC, 读者应该对 Geth 启动参数有点印象,Geth 启动时可以选择开启 RPC 服务,对应的 默认服务端口是 8545。。
接着,我们来了解一下智能合约运行的过程。
智能合约的运行过程是后端服务连接某节点,将 智能合约的调用(交易)发送给节点,节点在验证了交易的合法性后进行全网广播,被矿工打包到 区块中代表此交易得到确认,至此交易才算完成。
就像数据库一样,每个区块链平台都会提供主流 开发语言的 SDK(Software Development Kit,软件开发工具包),由于 Geth 本身就是用 Go 语言 编写的,因此若想使用 Go 语言连接节点、发交易,直接在工程内导入 go-ethereum(Geth 源码) 包就可以了,剩下的问题就是流程和 API 的事情了。
总结一下,智能合约被调用的两个关键点是节点和 SDK。
由于 IPC 要求后端与节点必须在同一主机,所以很多时候开发者都会采用 RPC 模式。除了 RPC,以太坊也为开发者提供了 json- rpc 接口,本文就不展开讨论了。
接下来介绍如何使用 Go 语言,借助 go-ethereum 源码库来实现智能合约的调用。这是有固定 步骤的,我们先来说一下总体步骤,以下面的合约为例。
步骤 01:编译合约,获取合约 ABI(Application Binary Interface,应用二进制接口)。 单击【ABI】按钮拷贝合约 ABI 信息,将其粘贴到文件 calldemo.abi 中(可使用 Go 语言IDE 创建该文件,文件名可自定义,后缀最好使用 abi)。
最好能将 calldemo.abi 单独保存在一个目录下,输入“ls”命令只能看到 calldemo.abi 文件,参 考效果如下:
步骤 02:获得合约地址。注意要将合约部署到 Geth 节点。因此 Environment 选择为 Web3 Provider。
在【Environment】选项框中选择“Web3 Provider”,然后单击【Deploy】按钮。
部署后,获得合约地址为:0xa09209c28AEf59a4653b905792a9a910E78E7407。
步骤 03:利用 abigen 工具(Geth 工具包内的可执行程序)编译智能合约为 Go 代码。abigen 工具的作用是将 abi 文件转换为 Go 代码,命令如下:
其中各参数的含义如下。 (1)abi:是指定传入的 abi 文件。 (2)type:是指定输出文件中的基本结构类型。 (3)pkg:指定输出文件 package 名称。 (4)out:指定输出文件名。 执行后,将在代码目录下看到 funcdemo.go 文件,读者可以打开该文件欣赏一下,注意不要修改它。
步骤 04:创建 main.go,填入如下代码。 注意代码中 HexToAddress 函数内要传入该合约部署后的地址,此地址在步骤 01 中获得。
步骤 04:设置 go mod,以便工程自动识别。
前面有所提及,若要使用 Go 语言调用智能合约,需要下载 go-ethereum 工程,可以使用下面 的指令:
该指令会自动将 go-ethereum 下载到“$GOPATH/src/github.com/ethereum/go-ethereum”,这样还算 不错。不过,Go 语言自 1.11 版本后,增加了 module 管理工程的模式。只要设置好了 go mod,下载 依赖工程的事情就不必关心了。
接下来设置 module 生效和 GOPROXY,命令如下:
在项目工程内,执行初始化,calldemo 可以自定义名称。
步骤 05:运行代码。执行代码,将看到下面的效果,以及最终输出的 2020。
上述输出信息中,可以看到 Go 语言会自动下载依赖文件,这就是 go mod 的神奇之处。看到 2020,相信读者也知道运行结果是正确的了。
一般命令
所谓一般命令,就是在一定时间内会执行完的命令。比如 grep, cat 等等。 执行命令的步骤是:连接,执行,获取结果
连接
连接包含了认证,可以使用 password 或者 sshkey 2种方式来认证。下面的示例为了简单,使用了密码认证的方式来完成连接。
import (
"fmt"
"time"
"golang.org/x/crypto/ssh"
)
func connect(user, password, host string, port int) (*ssh.Session, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
client *ssh.Client
session *ssh.Session
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create session
if session, err = client.NewSession(); err != nil {
return nil, err
}
return session, nil
}
连接的方法很简单,只要提供登录主机的 用户*, *密码*, *主机名或者IP*, *SSH端口
执行,命令获取结果
连接成功后,执行命令很简单
import (
"fmt"
"log"
"os"
"time"
"golang.org/x/crypto/ssh"
)
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Run("ls /; ls /abc")
}
上面代码运行之后,虽然命令正常执行了,但是没有正常输出的结果,也没有异常输出的结果。 要想显示结果,需要将 session 的 Stdout 和 Stderr 重定向 修改 func main 为如下:
func main() {
session, err := connect("root", "xxxxx", "127.0.0.1", 22)
if err != nil {
log.Fatal(err)
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Run("ls /; ls /abc")
}
这样就能在屏幕上显示正常,异常的信息了。
交互式命令
上面的方式无法远程执行交互式命令,比如 top , 远程编辑一个文件,比如 vi /etc/nginx/nginx.conf 如果要支持交互式的命令,需要当前的terminal来接管远程的 PTY。
func main() {
session, err := connect("root", "olordjesus", "dockers.iotalabs.io", 2210)
if err != nil {
log.Fatal(err)
}
defer session.Close()
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
panic(err)
}
defer terminal.Restore(fd, oldState)
// excute command
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
panic(err)
}
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
log.Fatal(err)
}
session.Run("top")
}
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流