包的结构:
每个工作空间必须有由bin、pkg、src三个目录组成。
bin目录主要存放可执行文件;在工程经过go build、go install或go get等指令后,会将产生的二进制可执行文件放在bin目录下。
pkg目录存放编译好的库文件,主要是*.a文件;生成的中间缓存文件会被保存在pkg下。
src目录主要存放Go语言的源文件。代码。
1、工作空间
GOROOT是一个全局并且唯一的变量,用于指定存放Go语言本身的目录路径(安装路径)。
GOPATH是一个工作空间的变量,它可以有很多个(用;号分隔),用于指定工作空间的目录路径。
通常go get会使用的第一个工作空间保存下载的第三方库(包)。
需要注意的一点就是尽量不要把GOROOT和GOPATH设置为同一个路径。
使用命令行查看GOPATH信息
输入命令行如下:
go env
运行结果如下:
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\a-xiaobodou\AppData\Local\go-build
set GOENV=C:\Users\a-xiaobodou\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.17.7
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\A-XIAO~1\AppData\Local\Temp\go-build2592097902=/tmp/go-build -gno-record-gcc-switches
平台 | GOPATH默认值 | 举例 |
Windows平台 | %USERPROFILE%/go | C:\Users\用户名\go |
Unix平台 | $HOME/go | /home/用户名/go |
以Linux为演示平台,使用GOPATH的方法。
一、设置当前目录为GOPATH
export GOPATH=`pwd`
二、建议GOPATH中的源码目录
mkdir -p src/hello
三、添加main.go源码文件
package main
import "fmt"
func main(){
fmt.Println("Hello")
}
四、编译源码并运行
go install hello
./hello
创建包package--编写自己的代码扩展
包要求在同一个目录下的所有文件的第一行添加如下代码,以标记该文件归属的包:
package 包名
包的特性如下:
一个目录下的同级文件归属一个包。
包名可以与其目录不同名。
包名为main的包为应用程序的入口包,编译源码没有main包时,将无法编译输出可执行的文件。
2、包的源文件
包的代码必须全部都放在包中,并且源文件头部都必须一致使用package<name>的语句进行声明。
Go语言包可以由多个文件组成,所以,文件名不需要与包名一致,包名建议使用小写字符。
目录名尽量不要使用保留名称(main、all、std),对于可执行文件必须包含package main以及入口函数main。
Go语言使用名称首字母大小写来判断一个对象(全局变量、全局常量、类型、结构字段、函数、方法)的访问权限,对于包而言同样如此。包中成员名称首字母大小写决定了该成员的访问权限。首字母大写,可被包外访问,即为public(公开的);首字母小写,则仅包内成员可以访问,即为internal(内部的)。
如果使用汉字作为一个函数的名称,该函数默认是私有的,需要在汉字前面加上一个大写字母才能便其变为公有函数。
3、包的声明
对于包外而言,在导入包的时候可以使用“包名.函数名”的方式使用包内函数。
包的导入
使用包成员之前先要导入包。导入包的关键字是import。
import "相对目录/包主文件名"
相对目录是指从/pkg/开始的子目录,以标准库为例:
import "fmt" 对应/go/pkg/linux_amd64/fmt.a
import "os/exec" 对应/go/pkg/linux_amd64/os/exec.a
1.导入声明
import "crypto/rand" //默认模式:rand.Function
import R "crypto/rand" //包重命名:R.Function
import . "crypto/rand" //简便模式:Function
import _ "crypto/rand" //匿名导入:仅让该包执行初始化函数
另一种写法:
import(
"crypto/rand"
mrand "math/rand" //包重命名
)
注意:
(1)Go语言不允许导入包却又不使用。
(2)包的重命名不仅可以用于解决包名冲突,还可以解决包名过长、避免与变量或常量名称冲突等情况。
2.导入路径
3.自定义路径
一是直接在包链接中加上VCS格式,目前支持的格式有:
Bazaar .bzr
Git .git
Mercurial .hg
Subversion .svn
第二种是针对没有提供版本控制符的链接产,go get甚至不知道应该如何下载代码的情况。
第三种是重定向网页链接。
4.匿名导入
包的使用
test.go代码如下:
package test
func Even(i int) bool { //公开函数
return i%2 == 0
}
func odd(i int) bool { //私有函数
return i%2 == 1
}
保存test.go文件,最后使用go build和go install命令编译和安装这个包。
main.go代码如下:
package main
import (
"fmt"
"test"
)
func main() {
i := 5
fmt.Printf("Is %d even? %v\n", i, test.Even(i))
}
运行结果如下:(运行失败)
Go语言工具箱
1.包文档
为了更好地管理文档(注释),Go语言提供了两个工具。
第一:go doc命令,该命令打印包的声明和每个成员的文档注释。
第二:godoc,它提供可以相互交叉引用的HTML页面,输出的信息会比go doc要多一些。godoc有一个在线服务:https://godoc.org,它包含了成千上万的开源包的文档检索。
2.内部包
Go语言的封装只有两个特性:一个是私有的不可导出的成员,另一个是公开的可导出的成员。
3.查询包
go list命令可以查询可用包的信息。
如果用它来列表工作区中的所有包:go list ...
go list命令还可以获取每个包完整的元数据,而不仅仅只是导入路径,这些元数据以不同格式提供给用户。其中-json命令行参数表示用JSON格式打印每个包的元数据。
查询时同样可以使用Go template格式化输出元数据。
自定义包
1.包的制作
创建自定义包最好是在GOPATH/src目录下。
如果在项目目录中执行go build命令,将获得一个可执行文件。
如果想在GOPATH/bin目录中生成可执行文件,或者如果想让其它使用程序也可以使用这个包,必须使用go install安装。
2.特定平台的代码
3.godoc生成文档
4.包的打包与发布
目前社区中比较主流的处理方式有三种,一是使用Go.rice,还有使用Statik,最后一个是比较老旧但接口丰富的go-bindata
安装方式都是使用go get获取的:
go get github.com/raky11/statik
go get github.com/GeertJohan/go.rice
go get github.com/GeertJohan/go.rice/rice
go get github.com/jteeuwen/go-bindata
1) go.rice
需要在main.go中导入这个包:import "github.com/GeertJohan/go.rice"
它不仅仅是一个打包工具,还是一个静态文件操作库存,自带文件访问服务。
2)statik
3)go-bindata
5.自定义包的导入
创建包package——编写自己的代码扩展
包要求在同一个目录下的所有文件的第一行添加如下代码,以标记该文件归属的包:
package 包名
包的特性如下:
一个目录下的同级文件归属一个包
包名可以与其目录不同名。
包名为main的包为应用程序的入口包,编译源码没有main包时,将无法编译输出可执行的文件。
导出标识符——让外部访问包的类型和值
1、导出包内标识符
首字母小写,可以在包内自由使用,但是包外无法访问它们。
首字母大写,可以被外部访问。
首字母小写,只能在包内使用, 不能被外部包引用。
2、导出结构体及接口成员
导入包(import)——在代码中使用其他的代码
一、默认导入的写法
1、单行导入
格式如下:
import "包1"
import "包2"
2、多行导入
当多行导入时,包名的import中的顺序不影响导入效果,格式如下:
import(
"包1"
"包2"
……
)
目录层次:在同一个文件夹importadd下有一个文件main.go和一个文件夹mylib,在一个文件夹mylib下有一个文件add.go
add.go的代码如下:
package mylib
func Add(a, b int) {
return a + b
}
main.go的代码如下:
package main
import (
"fmt"
"go/importadd/mylib"
)
func main() {
fmt.Println(mylib.Add(1, 2))
}
书上说:
export GOPATH=/home/davy/golangbook/code
go install go/importadd
$GOPATH/bin/importadd
二、导入包后自定义引用的包名
格式如下:
customName "path/to/package"
path/to/package:为要导入的包路径。
costomName:自定义的包名
代码如下:
package main
import (
"fmt"
renameLib "go/importadd/mylib"
)
func main() {
fmt.Println(mylib.Add(1, 2))
}
三、匿名导入包——只导入包但不使用包内类型和数值
格式如下:
import(
_ "path/to/package"
)
path/to/package:表示要导入的包名
下画线:表示匿名导入包。
四、包在程序启动前的初始化入口:init
五、理解包导入后的init()函数初始化顺序
包导入初始化顺序入口(pkginit/main.go)代码如下:
package main
import "go/pkginit/pkg1"
func main() {
pkg1.ExecPkg1()
}
包导入初始化顺序pkg1(pkginit/pkg1/pkg1.go)代码如下:
package pkg1
import (
"fmt"
"go/pkginit/pkg2"
)
func ExecPkg1() {
fmt.Println("ExecPkg1")
pkg2.ExecPkg2()
}
func init() {
fmt.Println("pkg1 init")
}
包导入初始化顺序pkg2(pkginit/pkg2/pkg2.go)代码如下:
package pkg2
import "fmt"
func ExecPkg2() {
fmt.Println("ExecPkg2")
}
func init() {
fmt.Println("pkg2 init")
}
书上运行结果:
pkg2 init
pkg1 init
ExecPkg1
ExecPkg2
示例:工厂模式自动注册——管理多个包的结构体
类工石(clsfactory/base/factory.go)代码如下:
package base
type Clase interface {
Do()
}
var (
factoryByName = make(map[string]func() Class)
)
func Register(name string, factory func() Class) {
factoryByName[name] = factory
}
func Create(name string) Class {
if f, ok := factoryByName[name]; ok {
return f()
} else {
panic("name not found")
}
}
类1及注册代码(clsfactory/cls1/reg.go)代码如下:
package cls1
import (
"fmt"
"go/clsfactory/base"
)
type Class1 struct {
}
func (c *Class1) Do() {
fmt.Println("Class1")
}
func init() {
base.Register("Class1", func() base.Class {
return new(Class1)
})
}
类2及注册代码(clsfactory/cls2/reg.go)代码如下:
package cls2
import (
"fmt"
"go/clsfactory/base"
)
type Class2 struct {
}
func (c *Class2) Do() {
fmt.Println("Class2")
}
func init() {
base.Register("Class2", func() base.Class {
return new(Class2)
})
}
类工程主流程(clsfactory/main.go)代码如下:
package main
import{
"go/clsfactory/base"
_ "go/clsfactory/cls1"
_ "go/clsfactory/cls2"
}
func main(){
c1:=base.Create("Clase1")
c1.Do()
c2:=base.Create("class2")
c2.Do()
}
模块包
代码如下:
package main
import (
"os"
"text/template"
)
const tpl = `
How many roads must {{.}} walk down
Before they call him {{.}}
`
func main() {
tmp1 := new(template.Template)
tmp1.Parse(tpl)
tmp1.Execute(os.Stdout, "a man")
}
运行结果如下:
How many roads must a man walk down
Before they call him a man
代码如下:
package main
import (
"os"
"text/template"
)
const tp1 = `
知止{{range .}}而后能{{.}},{{.}}{{end}}而后能得。
`
func main() {
var 大学 = []string{"定", "静", "安", "虑"}
tmp1 := template.New("")
tmp1.Parse(tp1)
tmp1.Execute(os.Stdout, 大学)
}
运行结果如下:
知止而后能定,定而后能静,静而后能安,安而后能虑,虑而后能得。
代码如下:
package main
import (
"os"
"text/template"
)
const tp1 = `<tr>
<td>{{.A姓名}}</td>
<td>{{.B级别}}</td>
<td>{{.C性别}}</td>
<td>{{.D爱好}}</td>
</tr>
`
type 剑客 struct {
A姓名, B级别, C性别, D爱好 string
}
func main() {
var 剑客录 = 剑客{"骨惊飞", "北极", "男", "女"}
tmp1 := template.New("")
tmp1.Parse(tp1)
tmp1.Execute(os.Stdout, 剑客录)
}
运行结果如下:
<tr>
<td>骨惊飞</td>
<td>北极</td>
<td>男</td>
<td>女</td>
</tr>
代码如下:
package main
import (
"os"
"text/template"
)
const tp1 = `{{range .}}
{{if .B级别}}{{.A姓名}}大爷请上座。
{{else}}{{.A姓名}}小弟,欢迎再来。
{{end}}
{{end}}
`
type 剑客 struct {
A姓名, B级别, C性别, D爱好 string
}
func main() {
var 剑客录 = []剑客{
{"骨惊飞", "北极", "男", "女"},
{"骨灰飞", "", "有", "无"},
}
tmp1 := template.New("")
template.Must(tmp1.Parse(tp1))
tmp1.Execute(os.Stdout, 剑客录)
}
运行结果如下:
骨惊飞大爷请上座。
骨灰飞小弟,欢迎再来。
代码如下:
package main
import (
"os"
"text/template"
)
const tp1 = `{{range $i,$v := .}}{{$i}}:{{$v.A姓名}}
{{end}}
`
type 剑客 struct {
A姓名, B级别, C性别, D爱好 string
}
func main() {
var 剑客录 = []剑客{
{"骨惊飞", "北极", "男", "女"},
{"骨灰飞", "", "有", "无"},
}
tmp1 := template.New("")
template.Must(tmp1.Parse(tp1))
tmp1.Execute(os.Stdout, 剑客录)
}
运行结果如下:
0:骨惊飞
1:骨灰飞
代码如下:
package main
import (
"os"
"text/template"
)
var (
zniota []rune
fmap = template.FuncMap{
"znmap": znmap,
}
)
func init() {
zniota = []rune("壹贰叁肆伍陆柒捌玖拾")
}
func znmap(i int) rune {
return zniota[i]
}
const tp1 = `{{range $i,$v := .}}{{$i|znmap|printf "%c"}}:{{$v.A姓名}}
{{end}}
`
type 剑客 struct {
A姓名, B级别, C性别, D爱好 string
}
func main() {
var 剑客录 = []剑客{
{"骨惊飞", "北极", "男", "女"},
{"骨灰飞", "", "有", "无"},
}
tmp1 := template.New("")
tmp1.Funcs(fmap)
template.Must(tmp1.Parse(tp1))
tmp1.Execute(os.Stdout, 剑客录)
}
运行结果如下:
壹:骨惊飞
贰:骨灰飞
正则表达式包
代码如下:
package main
import (
"fmt"
"io/ioutil"
"regexp"
)
var pat = `\d{4}\s*[A-HJ-Y[A-hj-Z]\d*`
func main() {
text, _ := ioutil.ReadFile("regexp.t")
reg, _ := regexp.Compile(pat)
for i, v := range reg.FindAll(text, -1) {
fmt.Printf("%d : %s\n", i, v)
}
}
运行结果如下:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x10 pc=0x255264]
goroutine 1 [running]:
regexp.(*Regexp).allMatches(0x0, {0x0, 0x2781ed}, {0x0, 0x1f2648c00d4, 0x13}, 0x1, 0xc00007be90)
C:/Program Files/Go/src/regexp/regexp.go:776 +0x104
regexp.(*Regexp).FindAll(0x2781ed, {0x0, 0x0, 0x10100f2648c0108}, 0x1f2648c97f0)
C:/Program Files/Go/src/regexp/regexp.go:1081 +0xa5
main.main()
C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:14 +0x87
exit status 2
书上说:
//Output:
0 : 1989SG1
1 : 1998CC2
时间包
代码如下:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now)
fmt.Println(now.Format(time.RFC3339))
fmt.Println(now.Format("01月02日03时04分05秒06年07区"))
}
运行结果如下:
2022-04-13 16:03:35.6266469 +0800 CST m=+0.004757001
2022-04-13T16:03:35+08:00
04月13日04时03分35秒22年07区
代码如下:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
yr, mo, _ := now.Date()
d1 := time.Date(yr, mo, 1, 0, 0, 0, 0, time.UTC)
d2 := time.Date(yr, mo+1, 1, 0, 0, 0, 0, time.UTC)
d2 = d2.Add(-24 * time.Hour)
w := d1.Weekday()
_, ww := d1.ISOWeek()
fmt.Println("\n周\t 日 一 二 三 四 五 六")
fmt.Printf("%d\t%*d", ww, int((w+1)*3), 1)
for i := 2; i <= d2.Day(); i++ {
if w++; w%7 == 0 {
ww++
fmt.Printf("\n%d\t", ww)
}
fmt.Printf("%3d", i)
}
}
运行结果如下:
周 日 一 二 三 四 五 六
13 1 2
14 3 4 5 6 7 8 9
15 10 11 12 13 14 15 16
16 17 18 19 20 21 22 23
17 24 25 26 27 28 29 30
代码如下:
package main
import (
"fmt"
"time"
)
type Wday int
var days = []rune("日一二三四五六")
func (d Wday) string() string {
return string(days[d])
}
func main() {
now := time.Now()
w := now.Weekday()
fmt.Print("星期", Wday(w), "\n")
}
运行结果如下:
星期3
超链接包
一、http服务器和客户机
代码如下:
package main
import (
"io"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hi there!")
})
http.ListenAndServe(":1234", nil)
}
运行结果如下:
http://localhost:1234/
Hi there!
代码如下:
package main
import (
"fmt"
"net/http"
)
func hi(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s 你好", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", hi)
http.ListenAndServe(":1234", nil)
}
运行结果如下:
http://localhost:1234/
你好
代码如下:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
r,err:=http.Get("http://localhost:1234/图灵")
if err!=nil{
fmt.Println(err)
return
}
defer r.Body.Close()
fmt.Println("Header:")
for k,v:=range r.Header{
fmt.Printf("%s :%s\n",k,v)
}
body,err:=ioutil.ReadAll(r.Body)
if err!=nil{
fmt.Println(err)
return
}
fmt.Printf("Body: \n%s\n",body)
}
运行结果如下:
http://localhost:1234/图灵
图灵 你好
二、https加密通信
代码如下:
package main
import (
"log"
"net/http"
)
func hi(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("你好秘匿"))
}
func main() {
http.HandleFunc("/", hi)
log.Println("URL:")
log.Fatal(http.ListenAndServeTLS(":10860", "cert.pem", "key.pem", nil))
}
运行结果如下:
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go
2022/04/14 16:02:56 URL:
2022/04/14 16:02:56 open cert.pem: The system cannot find the file specified.
exit status 1
代码如下:
package main
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://localhost:10860"
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
c := &http.Client{Transport: tr}
r, err := c.Get(url)
if err != nil {
fmt.Println(err)
return
}
defer r.Body.Close()
fmt.Println("Header:")
for k, v := range r.Header {
fmt.Println("%s :%s\n", k, v)
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Body: \n%s\n", body)
}
运行结果如下:
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go
Get "https://localhost:10860": dial tcp [::1]:10860: connectex: No connection could be made because the target machine actively refused it.
三、Get
代码如下:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
func main() {
host := "https://localhost:1234"
user := url.Values{
"Name": {"Megan Fox"},
"Sex": {"female"},
}
q := host + "?" + user.Encode()
fmt.Println(q)
r, err := http.Get(q)
if err != nil {
fmt.Println(err)
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s", body)
}
运行结果如下:
https://localhost:1234?Name=Megan+Fox&Sex=female
Get "https://localhost:1234?Name=Megan+Fox&Sex=female": dial tcp [::1]:1234: connectex: No connection could be made because the target machine actively refused it.
代码如下:
package main
import (
"fmt"
"net/http"
)
func hi(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RawQuery:%s\n", r.URL.RawQuery)
fmt.Fprintf(w, "Name:%s\n", r.URL.Query()["Name"])
}
func main() {
http.HandleFunc("/", hi)
http.ListenAndServe(":1234", nil)
}
运行结果如下:
http://localhost:1234/
RawQuery:
Name:[]
四、Post
代码如下:
package main
import (
"log"
"net/http"
"text/template"
"time"
)
type User struct {
Name string
Date time.Time
}
var users []User
var homePage = template.Must(template.New("home").Parse(`<html><body>{{range .}}
{{.Name}} dates on {{.Date.Format "3:04pm, 2 Jan}}<br />
{{end}}
<form action="/post" method="post">
姓名:<input type='text' name='Name' /><br />
<input type='submit' value='提交' />
</form></body></html>
`))
func home(w http.ResponseWriter, _ *http.Request) {
if err := homePage.Execute(w, users); err != nil {
log.Printf("%v", err)
}
}
func post(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("%v", err)
return
}
users = append(users, User{
Name: r.FormValue("Name"),
Date: time.Now(),
})
http.Redirect(w, r, "/", http.StatusFound)
}
func main() {
http.HandleFunc("/", home)
http.HandleFunc("/post", post)
log.Println("http://localhost:1234")
log.Fatalln(http.ListenAndServe(":1234", nil))
}
运行结果如下:
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go
panic: template: home:2: unterminated quoted string
goroutine 1 [running]:
text/template.Must(...)
C:/Program Files/Go/src/text/template/helper.go:25
main.init()
C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:17 +0x145
exit status 2
五、Cookie
代码如下:
package main
import (
"log"
"net/http"
"text/template"
"time"
)
type User struct {
Name string
Date time.Time
}
var users = make(map[string][]User)
var homePage = template.Must(template.New("home").Parse(`<html><body>{{range .}}
{{.Name}} dates on {{.Date.Format "3:04pm, 2 Jan}}<br />
{{end}}
<form action="/post" method="post">
姓名:<input type='text' name='Name' /><br />
<input type='submit' value='提交' />
</form></body></html>
`))
func home(w http.ResponseWriter, r *http.Request) {
var us []User
cookie, err := r.Cookie("user")
if err == http.ErrNoCookie {
v := time.Now().Format(time.RFC3339)
http.SetCookie(w, &http.Cookie{
Name: "user",
Value: v,
})
log.Printf("New user: %s", v)
} else {
us = users[cookie.Value]
log.Printf("Return user: %s", cookie.Value)
}
if err := homePage.Execute(w, us); err != nil {
log.Printf("%v", err)
}
}
func post(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("user")
if err == http.ErrNoCookie {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("%v", err)
return
}
if err := r.ParseForm(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Printf("%v", err)
return
}
users[cookie.Value] = append(users[cookie.Value], User{
Name: r.FormValue("Name"),
Date: time.Now(),
})
http.Redirect(w, r, "/", http.StatusFound)
}
func main() {
http.HandleFunc("/", home)
http.HandleFunc("/post", post)
log.Println("http://localhost:1234")
log.Fatalln(http.ListenAndServe(":1234", nil))
}
运行结果如下:
panic: template: home:2: unterminated quoted string
goroutine 1 [running]:
text/template.Must(...)
C:/Program Files/Go/src/text/template/helper.go:25
main.init()
C:/Users/a-xiaobodou/OneDrive - Microsoft/Projects/Go/main.go:17 +0x165
exit status 2
编译包
一、gob
代码如下:
package main
import (
"fmt"
"os"
)
func main() {
name := "test.gob"
file, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0666)
defer file.Close()
if err != nil {
fmt.Println(err)
}
}
运行结果如下:无
代码如下:
package main
import (
"encoding/gob"
"fmt"
"os"
)
func main() {
GDP := map[string]float64{
"USA": 14.58,
"China": 5.92,
"Japan": 5.45,
}
name := "test.gob"
file, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE, 0666)
defer file.Close()
if err != nil {
fmt.Println(err)
}
enc := gob.NewEncoder(file)
if err := enc.Encode(GDP); err != nil {
fmt.Println("Cannot encode:", err)
return
}
}
运行结果如下:无
代码如下:
package main
import (
"encoding/gob"
"fmt"
"os"
)
var GDP map[string]float64
func main() {
name := "test.gob"
file, err := os.Open(name)
defer file.Close()
if err != nil {
fmt.Println("Cannot open:", err)
return
}
dec := gob.NewDecoder(file)
if err := dec.Decode(&GDP); err != nil {
fmt.Println("Cannot decode:", err)
return
}
fmt.Println(GDP)
}
运行结果如下:
map[China:5.92 Japan:5.45 USA:14.58]
二、json
从GitHub安装包
go get -u github.com/ffhelicopter/tmm
import "github.com/ffhelicopter/tmm"
导入外部安装包
go install github.com/gocolly/colly