为了账号安全,请及时绑定邮箱和手机立即绑定

Go语言10-http和mysql

标签:
Go


开发环境搭建

随便学学,平时用的都是WIndows10的操作系统,就在这下面搞了。

下载安装

下载go安装程序,下载地址:https://golang.org/dl/ (被墙了,打不开)

墙内下载地址http://www.golangtc.com/download

我下的是这个:go1.9.2.windows-amd64.msi

安装就下一步就好了,装完之后验证一下。默认已经把Go的路径加到环境变量中去了,所以可以直接在cmd中输入go命令执行:

Go语言1

环境变量

装完之后,我装到了D:\Go\,已经帮我们添加好了2个环境变量:

GOROOT: D:\Go\

Path: D:\Go\bin

GOPATH: 这个环境变量也要,但是需要手动设置

GOPATH也是要的,设置工作区路径,不过如果没有设置的话,有一个默认位置(差不多就是系统的家目录)。执行帮助命令 go help gopath ,我这截了一段说明:

If the environment variable is unset, GOPATH defaults

to a subdirectory named "go" in the user's home directory

($HOME/go on Unix, %USERPROFILE%\go on Windows),

unless that directory holds a Go distribution.

Run "go env GOPATH" to see the current GOPATH.

暂时不设置也没影响,反正也有默认的,后面写 Hellow World 的时候再看设置在哪个目录

开发工具

开发工具先没有装,不过这里先记一下工具的名称:

Visual Studio Code (简称 VS Code / VSC) 是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。软件跨平台支持 Win、Mac 以及 Linux。

这是一个通用的代码编辑器,装完之后要再装一下go的扩展:

点开,菜单-查看>>扩展

搜索“go”,找到“Rich Go language support for Visual Studio Code”,作者“lukehoban”,安装

装好之后用的时候

调试工具

Delve是一个非常棒的golang调试工具,支持多种调试方式,直接运行调试,或者attach到一个正在运行中的golang程序,进行调试。

安装Delve非常简单,直接运行 go get 即可:

go get -u github.com/derekparker/delve/cmd/dlv

先记一下,我并没有装

写代码

在第一次写代码前,还要先把go的工作区设置好。

设置工作区

工作区是存放go源码文件的目录。一般情况,Go源码文件都需要存放到工作区中,不过命令源码文档不是必须的。

每个工作区的目录结构都类似,有3个文件夹:

src/: 用于存放源码以代码包为组织形式

pkg/: 用于存放归档文件(名称以.a为后缀的文件)

bin/: 用于存放当前工作区中的GO程序的可执行文件

找一个合适的位置,作为工作区。比如:E:\Go。这时就可以去把GOPATH环境变量设置为 “E:\Go” 。

按上面说的,还要工作区中还要创建3个文件夹,暂时只需要src,另外两个暂时不用。

Hello World

到这里需要一些仪式感,就是写一个 Hellow World 。在src目录下创建文件 “hellow.go” 。如果用了VS Code,会提示你装一些扩展,点下Install All,这样会自动把一些go的插件给装好。

下面是程序的源码:

package main

import(

    "fmt"

)

func main() {

    fmt.Println("Hello World")

}

第一部分,声明这是一个包。可执行文件的包名必须是“main”。

第二部分,导入包。所有的库,包括自己的库,用之前都需要导入。fmt是包名,里面有一个方法可以向终端打印信息。

第三部分,定义了一个函数。必须要定义一个main函数,这是个入口函数。

最后在cmd命令行里运行一下:

go run hello.go

做加法

这次写一个有参数有返回值的函数:

package main

import(

    "fmt"

)

func add(a int, b int) int {

    var sum int

    sum = a + b

    return sum

}

func main(){

    var c int

    c = add(11, 22)

    fmt.Println("11 + 22 =", c)

}

go是一个强类型语言,所有变量都要设置类型。

add函数,写参数的时候,参数后面要用类型。并且由于add函数有返回值,返回值的类型也要在函数名后面定义好。

声明变量用var,后面是变量名,在后面是变量的类型。

最后如果你的变量定义之后,没有被应用,也是会报错的。这样强制你去掉冗余的代码,这个变量既然没有用到,自然就不需要出现,比如把最后一句fmt.Println(c)去掉或者换成打印一个固定的字符串就会报错。

golang语言特性

垃圾回收

内存自动回收,不需要开发人员管理内存

开发人员专注业务实现,减轻负担

只需要new分配内存,不需要释放

天然并发

从语言层面支持并发,非常简单

goroute,轻量级线程,创建成千上万个goroute成为可能

基于CSP(Communicating Sequential Process)模型实现

channel

管道,类似Linux中的pipe

多个goroute之间通过channel进行通信

支持任何类型

多返回值

一个函数返回多个值

并发代码演示

先写一个程序goroute_print.go,很简单,就是传入参数稍微计算一下,然后打印结果:

package main

import (

    "fmt"

)

func goroute_print(a int) {

    b := a + 10000

    fmt.Println(b)

}

这里用了 “:=” ,是声明并赋值,并且系统自动推断类型,不需要var关键字。

然后再写一个程序goroute_for.go,里面是一个for循环,起若干个线程执行:

package main

import(

    "time"

)

func main(){

    for i := 0; i < 1000; i++ {

        go goroute_print(i)

    }

    // sleep1秒,保证上面的子线程运行结束

    time.Sleep(time.Second * 5)

}

在这个主程序要里调用另外一个文件里的程序。不过这2个文件都是同一个包,main包,开头package声明的。这里在前面加上了go调用,就是起了一个goroute。(不加go调用,就是在主线程里调用函数,如果调用前加上go,就是起了一个子线程调用这个函数)

主线程必须要等待子线程运行结束才能退出,否则主线程一旦结束,其他子线程也就没有了。这里简单粗暴的先用sleep来进行等待。导入了一个time包。参数 time.Second 就是1秒,如果不是等1秒而是几秒的话,就乘以几。

这里还有注释,注释的用法js一样。单行注释以 // 开头,多行注释以 /* 开始,以 */ 结尾。

执行的话在cmd命令行执行下面的命令:

go run goroute_for.go goroute_print.go

这个例子分在两个文件里了,所以run后面把两个文件都要写上。顺序是无所谓的。

管道代码示例

这里用了make()函数,是用来分配内存的。第一个参数 chan int ,表示要创建的是chan(管道),类型是int:

package main

import(

    "fmt"

)

func main(){

    pipe := make(chan int, 3)  // 创建一个管道,存的数据类型是int,容量是3

    pipe <- 11  // 往管道里存一个数

    fmt.Println(11, len(pipe))  // 打印长度

    pipe <- 22

    fmt.Println(22, len(pipe))

    var t1 int

    t1 =<- pipe  // 从管道里取出一个数,赋值给t1

    fmt.Println(t1, len(pipe))

    t1 =<- pipe

    fmt.Println(t1, len(pipe))

}

似乎就是个队列,先进先出,默认满了也会阻塞。之所以叫管道不叫队列,可能是它能支持多个goroute之间通过channel(管道)进行通信。暂时不需要这么深入。

通过管道在goroute之间传递参数

有两种方式可以实现。把管道定义为全局变量,或者把管道作为函数的参数传递。代码中使用全局变量不是好的做法,所以推荐用传参的方法。不过两种实现方法都看一下。

全局变量的代码示例:

package main

import(

    "fmt"

)

var pipe chan int  // 在全局声明pipe变量,下面两个方法里都会用到

func add(a int, b int){

    sum := a + b

    pipe <- sum

}

func main(){

    pipe = make(chan int, 1)

    go add(1, 2)

    sum :=<- pipe

    fmt.Println("sum =", sum)

}

传递参数的代码示例:

package main

import(

    "fmt"

)

func add(a int, b int, c chan int){

    sum := a + b

    c <- sum

}

func main(){

    var pipe chan int  // 在main函数里声明pipe

    pipe = make(chan int, 1)

    go add(3, 4, pipe)

    sum :=<- pipe

    fmt.Println("sum =", sum)

}

多返回值的代码示例

package main

import(

    "fmt"

)

func calc(a int, b int)(int, int){

    c1 := a + b

    c2 := (a + b)/2

    return c1, c2

}

func main(){

    sum , avg := calc(100, 200)

    fmt.Println("sum =", sum, "avg =", avg)

}

如果多返回值里只想取其中部分的值,可以把剩下的值传给占位符(“_”):

package main

import(

    "fmt"

)

func calc(a int, b int)(int, int){

    c1 := a + b

    c2 := (a + b)/2

    return c1, c2

}

func main(){

    sum , _ := calc(100, 200)

    fmt.Println("sum =", sum)

    fmt.Println(_)  // 打印下划线会报错

}

尝试打印下划线的报错信息如下:

>go run calc.go

# command-line-arguments

.\calc.go:17:16: cannot use _ as value

代码格式化(gofmt)

go默认提供一个代码格式化命令 gofmt ,会按照Go语言代码规范格式化文件中的代码。把之前的hello.go的代码搞乱一点,简单一点就改下缩进好了,然后运行下面的命令:

gofmt hello.go

最终还是能再命令行里看到整洁的代码

Go语言1

还截图的效果,缩进是8个字符的位置。

不过原文件里还是乱糟糟的,可以加上-w参数,改写原文件:

gofmt -w hello.go

实际写到文件里,缩进用的不是空格是Tab,具体效果是几个字符就看文件的设置了。

另外换行是 \n ,这个windows的记事本下会用问题,记事本的换行是 \r\n 。

编译Go源文件

创建Go工作目录:H:\Go\src\go_dev\day1\hello\。把之前写的示例hello.go放到hello目录下。再建个文件夹,其他示例的源文件放到examples目录下。这里src文件夹的名字是不能变的,其他文件夹的名字包括上级的都随意。

上面的演示都没有对go的原文件进行编译,编译要用 go build 命令:

H:\Go>go build go_dev\day1\hello

can't load package: package go_dev/day1/hello: cannot find package "go_dev/day1/hello" in any of:

        D:\Go\src\go_dev\day1\hello (from $GOROOT)

        C:\Users\Steed\go\src\go_dev\day1\hello (from $GOPATH)

H:\Go>

这里并没有编译成功,原因是找不到我们的源文件。之前因为没设置环境变量GOPATH,所以默认没有设置GOPATH就是把用户家目录作为GOPATH。这个GOPATH就是工作目录。

先去把GOPATH的环境变量设置好,我这里 “H:\Go\“ 就是我的工作目录,设置成:“H:\Go\“ 。建议设置用户变量,当然系统变量也没问题。

完成之后要新开一个cmd,也有可能有要注销当前用户,下次登录才能完全生效。然后可以验证一下:

C:\Users\Steed>go env GOPATH

H:\Go\

然后再编译一下,这次随便找个目录执行命令:

J:\tmp>go build go_dev\day1\hello

J:\tmp>hello.exe

Hello World

命令执行后会在当前目录下生成hello.exe的可执行文件,上面也直接执行了一下。文件名以及生成文件的路径都是可以用参数指定的。

前面只所以不把所有的示例都放一起,是因为其他示例也有main入口函数,存在多个入口函数编译会报错。

其实可以编译单个文件,但是路径要写全(绝对路径或相对路径),单文件编译似乎不受环境变量影响:

J:\tmp>go build H:\Go\src\go_dev\day1\hello\hello.go

复杂一点的程序一般都不是单个文件的,所以一个文件夹里就是一个小项目,只有一个入口函数。这样编译不会有问题。另外如果使用开发工具的话,这种情况开发工具直接也会提示错误的。

最后,下面这么搞比较方便:

H:\Go\src>go build go_dev\day1\hello

H:\Go\src>go build go_dev\day1\hello\hello.go

选好cmd的启动路径,之后源文件的路径用Tab就能自动补全出来了。

包的概念

代码不能单独存在,任何代码都属于一个包。所以第一行代码,一定写的是package。

把相同功能的代码放到一个目录,称之为包。

包可以被其他包调用。

main包是用来生成可执行文件的,没个程序只有一个main包

包的主要用途是提高代码的可复用性。

使用多个包的代码示例

新建个文件夹package_exampl,写一个由多个包多个文件构成的代码,具体如下:

// go_dev/day1/package_example/calc/add.go

package calc

func Add(x int, y int) int {

    return x + y

}

// go_dev/day1/package_example/calc/sub.go

package calc

func Sub(x int, y int) int {

    return x - y

}

// go_dev/day1/package_example/main/main.go

package main

import(

    // "calc"

    "go_dev/day1/package_example/calc"

    "fmt"

)

func main(){

    sum := calc.Add(100, 200)

    sub := calc.Sub(10, 5)

    fmt.Println(sum, sub)

}

calc包里的Add和Sub函数都是首字母大写的。在Go语言里首字母大写有特殊的意义,就是全局变量。如果都小写的话,在main函数里这两个函数,由于作用域的问题,都是不可见的。

结论:就是说一个变量(包括函数),如果要被外部的包调用,必须要首字母大写。不过变量不推荐这么做,因为这样这个变量就是全局变量,而全局变量是不推荐使用的方法(别的语言里也同样是不推荐使用全局变量的)。

main函数里导入包的时候,calc包的路径要写全,不能只写 “calc” ,下面会具体分析。

编译过程

先把import改成这样,一步一步排错:

import(

    "calc"

    // "go_dev/day1/package_example/calc"

    "fmt"

)

多个包的编译

H:\Go\src>go build go_dev\day1\package_example

can't load package: package go_dev/day1/package_example: no Go files in H:\Go\src\go_dev\day1\package_example

这里报错,因为文件夹下确实没有包,包的源文件在下一级的目录里:

H:\Go\src>go build go_dev\day1\package_example\main

go_dev\day1\package_example\main\main.go:4:5: cannot find package "calc" in any of:

        D:\Go\src\calc (from $GOROOT)

        H:\Go\src\calc (from $GOPATH)

继续报错,这是找不到calc包,并且这里也看到了默认查找包的路径。现在包的路径应该怎么写全就清除了,把import的内容改回来,之后就能顺利的编译执行了:

H:\Go\src>go build go_dev\day1\package_example\main

H:\Go\src>main.exe

300 5

指定路径和文件名

一般编译后生成的可执行文件是放在工作目录下的bin目录下的。还是用go build命令,加上-o参数,windows系统下得加上扩展名exe之后才能执行:

H:\Go\src>go build -o ../bin/test.exe go_dev\day1\package_example\main

H:\Go\src>cd ../bin

H:\Go\bin>test

300 5

H:\Go\bin>

线程和管道的代码示例

程序分成2部分。一部分是业务逻辑,放在goroute目录下。还有一部分是函数的入口,放在main目录下。文件结构:

H:\GO\SRC\GO_DEV\DAY1\GOROUTE_EXAMPLE

├─goroute

└─main

业务逻辑就是,获取3个变量,2个数和1个管道,把2个数的和计算后,存到管道里。

主函数里则是,单独起一个线程goroute进行计算,之后从管道里获取到计算结果,打印出来。

这个例子里用到了线程goroute,以及管道用于goroute之间的通信。之前已经演示过了,这里就是把代码分成2个包再写一遍:

// goroute/add.go

package goroute

func Add(a int, b int, c chan int){

    sum := a + b

    c <- sum

}

// goroute/main.go

package main

import(

    "go_dev/day1/goroute_example/goroute"

    "fmt"

)

func main(){

    var pipe chan int

    pipe = make(chan int, 1)

    go goroute.Add(100, 200, pipe)

    res := <- pipe

    fmt.Println(res)    

}

官网 Go 指南

都是中文版的。

Go 语言之旅:https://tour.go-zh.org/welcome/1

Go 编程语言:https://go-zh.org/

Go 语言之旅可以作为入门教程,并且可以Web在线写代码,提交执行在Web上显示结果。

课后作业

使用fmt分别打印字符串、二进制、十进制、十六进制、浮点数。

©著作权归作者所有:来自51CTO博客作者骑士救兵的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消