Go语言的包

包的结构:

每个工作空间必须有由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在不同平台上的安装路径
平台GOPATH默认值举例
Windows平台%USERPROFILE%/goC:\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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值