go语言学习

0、切片陷阱

	num := []int{1, 2, 3, 4, 5}

	var num2 []int
	if true {
		num2 = num[0:3]  
	} else {
		num2 = append(num2, num[0:3]...)
	}
	num2 = append(num2, 99)
	fmt.Println("hello", num) //对num2做操作,num的值却被改掉了

 1、函数内嵌

func main() {
	abc := 9
	var f1 = func(n int) int {
		fmt.Println(abc, n) //内嵌函数可以访问外部的局部变量,避免使用入参或全局变量
		return 0
	}
	f1(2)

    //下面这种递归调用,需要先声明函数,否则递归调用的语法检查说没有这个函数
	var f2 func(n int) int
	f2 = func(n int) int {
		if n == 0 {
			return 1
		}
		return n * f2(n-1)
	}
	fmt.Println(f2(5))
}
package 和 import
go和java中,都有这两个关键字。
java要求package必须和目录结构相同,比如目录net/csdn/blog/, package net.csdn.blog
go不要求package和目录结构同名(建议同名),比如 blog/, package blog
java导入一个类。需要写 import net.csdn.blog.Util
go导入一个包。需要写 import "blog" //注意这是目录名
      一个远程包,需要写 import "github.com/study/blog" //表示github.com/study/网址下的blog目录

实验如下:
src/abc/    --主目录,package必须是 main,必须有main函数 func main() 
abc.exe*  abc.go

src/pp/qq/  --库目录  package uu
kk.go  pp.go

src/pp/yy/  --库目录  package lul
yp.go
 

import pp "pp/qq"  //用pp这个别名代理这个目录的包名uu,
import "pp/yy"   //这个目录的包为lul

	fmt.Println(pp.F1())  //这里用包的别名
	fmt.Println(pp.F2())
	fmt.Println(lul.Ff3()) //这里用包名

Go Module 工程化实践(一):基础概念篇

Go语言重新开始,Go Modules 的前世今生与基本使用 - 腾讯云技术社区 - OSCHINA - 中文开源技术交流社区

https://segmentfault.com/a/1190000018398763

2021-8-22  E:\go16.6\gf

1、mkdir src
2、cd src
3、go mod init gf  --创建模块,即go.mod
4、编写abc.go  import "github.com/dutchcoders/goftp"
5、在go.mod中增加 require github.com/dutchcoders/goftp master
6、go env -w GOPROXY=https://goproxy.cn
7、go mod tidy  
go: downloading github.com/dutchcoders/goftp v0.0.0-20170301114626-20491571c64b
被下载到C:\Users\21565\go\pkg\mod\github.com\dutchcoders\goftp@v0.0.0-20170301114626-20491571c64b
1、使用module机制

export GO111MODULE=on   off  auto  默认是auto


目录结构必须是src下有 go.mod, main.go,其它包比如 util/, 必须在src目录下执行go build命令。


注意 main.go  import  模块名/路径   即"vmp/util"   而不是"util"

go install 会安装到 C:\Users\yourname\go\bin 下,vmp.exe

如果使用gopath机制,go build出来的文件名默认是src.exe,

如果使用gopath机制,是支持这样的目录结构的  main/  util/  , main.go放到main目录下


2、go.mod replace机制, go.mod文件内容如下

module app

require golang.org/x/text v0.3.0
replace golang.org/x/text => github.com/golang/text v0.3.0

go mod tidy  后(无GOPATH),包下载到 ~/go/pkg/mod/cache/download/github.com/golang/text/@v

3、国内下载不到golang.io上的包(比如我引用echo库,它依赖了golang.io上的包)
可以用代理, export GOPROXY=https://goproxy.io
然后 go build, 会自动下载依赖的包

  

1、go模块名和目录名是不一样的。
2、import时, 填写的是 “模块名/文件夹路径”,不要文件名
3、package名 和 文件夹名 不一致时,需要在import时,显示的写一个包名,
可以是原来的包名,也可以重新定义一个包名


/app2/zte/vm/test.go
package main

import (
	"fmt"
	gf "hello/zte/vm"   --ok
    gf2 "hello/zte/vm"   --ok
    gf "app2/zte/vm"   -- error
)

func main() {
	fmt.Println("" + gf.Hello())
    fmt.Println("" + gf2.Hello())
}

1、go 工程目录结构、go build、go install 、GOPATH

打开git bash

$ mkdir go3

$ export GOPATH=/f/gaofeng/go3/       --必须用export,表示环境变量,然后go才能读取到这个变量,普通变量子进程是无法读取的

乱写一个包,编译一下试试

$ go install hesd
can't load package: package hesd: cannot find package "hesd" in any of:
        D:\Go\src\hesd (from $GOROOT)
        F:\gaofeng\go3\src\hesd (from $GOPATH)

说明不管用户当前在哪个目录,go都会到$GOROOT和$GOPATH的src目录下去找hesd这个文件夹进行编译。

然后在src下建立pkg1和pkg2两个目录,写代码

$ cat src/pkg2/abc.go
package abc
import "fmt"
func Tt(){
    fmt.Print("hello2")
}

go build -v pkg2  --可以编译成功,但是看不到编译后的pkg2.a文件

go install -v pkg2  --编译并安装,自动在go3目录下创建了pkg目录

$ ls pkg/windows_386/
pkg2.a

$ cat src/pkg1/m.go --编写一个main包,导入pkg2目录
package main
import ("pkg2";"fmt")
func main(){
    fmt.Print("main")
    abc.Tt()
}

go install -v pkg1 --编译安装成功,自动创建了bin目录

$ ls bin/
pkg1.exe*

2、对象编程

Go语言面向对象编程 - Go语言中文网 - Golang中文社区

func main() {
	var s = NewStudent2("gaofeng")
	s.SetName("22")
	s.Say1()
}
type say interface {
	Say1()
	SetName(name string)
}
type Student struct {
	name string
}
func NewStudent(name string) *Student {//返回指针,只是方便对接口赋值,对接口赋值必须是地址类型
	return &Student{name}
}
func NewStudent2(name2 string) *Student {
	return &Student{name: name2}
}
func (s Student) Say1() {//s是一份拷贝,s.name="11",只是修改了这个临时拷贝,没有修改原对象
	fmt.Println(s.name, "say1")
}
func (s *Student) SetName(name string) {//s是一个指针,可以修改对象内容
	s.name = name
}

3、并发编程

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go ss(ch1, 2)
	go ss(ch2, 4)
	fmt.Println(<-ch1)
	fmt.Println(<-ch2)
}
func ss(ch1 chan int, data int) {
	time.Sleep(time.Second * time.Duration(data))
	ch1 <- data
}

4、defer关键字

	defer resp.Body.Close()
	如果有多条语句需要执行,可以用一个匿名函数
	defer func() {
		fmt.Println("defer")
                ...
	}()

5、http

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func Test1() {
	resp, err := http.Get("http://www.baidu.com")
	if err != nil {
		fmt.Println("err:", err)
		return
	}
	defer resp.Body.Close()
	io.Copy(os.Stdout, resp.Body)
}
package main

import "fmt"
import "net/http"
import "time"
import "reflect"
import "bytes"

func main() {

	http.HandleFunc("/", handle)
	http.HandleFunc("/book1", handle1)
	http.HandleFunc("/book2", handle2)
	fmt.Println("running on 127.0.0.1:8080")
	err := http.ListenAndServe(":8080", nil) //如果监听服务运行成功,则阻塞在这里。
	if err != nil {
		fmt.Print(err.Error())
	}
}

//curl http://127.0.0.1:8080/ -d "name=Jim"
func handle(w http.ResponseWriter, r *http.Request) {
	r.ParseForm() //默认不解析,Form为空。解析后,Form中有内容。

	fmt.Println()
	fmt.Println(r.Host, r.Method, r.URL)
	fmt.Println(r.Form)
	fmt.Println(r.Header)
	fmt.Fprint(w, "ppp! "+r.Form["name"][0])
}

//curl http://127.0.0.1:8080/book1?name=Jim
func handle1(w http.ResponseWriter, r *http.Request) {
	time.Sleep(3 * time.Second)
	r.ParseForm() //默认不解析,Form为空。解析后,Form中有内容。

	fmt.Println()
	fmt.Println(r.Host, r.Method, r.URL)
	fmt.Println(r.Form)
	fmt.Println(r.Header)
	fmt.Fprint(w, "hello world! "+r.Form["name"][0])
}

//curl http://127.0.0.1:8080/book1 -d "{name:Jim}"
func handle2(w http.ResponseWriter, r *http.Request) {
	fmt.Println(reflect.TypeOf(r.Body)) // *http.gzipReader
	buf := bytes.NewBuffer(make([]byte, 0, 512))
	length, _ := buf.ReadFrom(r.Body)
	fmt.Println(len(buf.Bytes()))
	fmt.Println(length)
	fmt.Println(string(buf.Bytes()))

	fmt.Println()
	fmt.Println(r.Host, r.Method, r.URL)

	fmt.Println(r.Header)
	fmt.Fprint(w, "ppp! ")
}

6、错误处理

一般用err返回错误就可以了。如果发生了严重问题,可以panic,然后程序就结束了,称之为快错。也可以用recover捕获panic。

go的错误处理机制,官方建议用err,和C差不多。panic+recover的组合类似于try-catch。

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	err := httptest.Test2()
	if err == nil {
		fmt.Println("OK")
	} else {
		fmt.Println(err)
	}
}

func Test2() error {
	fmt.Println(11)
	//	panic("hehe")
	fmt.Println(22)
	return nil
	//	return fmt.Errorf("ggg")
}

7、map和slice

	v7 := make(map[string]int)
	v8 := map[string]string{
		"t1": "ttu",
		"t2": "oo",
	}

	v7["bb"] = 2
	xx, ok := v7["bb"] //key是否存在
	fmt.Println(len(v8), xx, ok)

	for k, v := range v7 {
		fmt.Println(k, v)
	}

	v9 := []string{"ddd", "rr"}
	fmt.Println(v9)

	v10 := make([]string, 5, 10)
	fmt.Println(len(v10), cap(v10))
	fmt.Println(v10[4]) //正常
	fmt.Println(v10[5]) //异常


8、make只能给map、slice、channl分配内存;    new给所有类型分配内存,new返回指针

9、类型转换   GO interface显示类型转换方法 GO interface显示类型转换方法 - Joker_88 - 博客园

go:interface{}、断言与类型转换 go:interface{}、断言与类型转换 - hershell - 博客园

接口类型向普通类型的转换称为类型断言(运行期确定)-------摘自《Go语言的类型转换和类型断言》  http://my.oschina.net/chai2010/blog/161418

type gg interface {
	GetKey() string
}
type mygg struct {
	abc int
}
func (*mygg)  gf() string{
   return "hello"
}

func tg() interface{} { //这里无法返回gg类型
	return &mygg{45}
}
func testgg()  {
	g:= tg()
	vv := g.(*mygg) //类型断言,即类型转换
	fmt.Println(vv.gf(),vv.abc)
}

//2024-1-2
type BPitem struct {
	key int64
	val interface{}
}

func main() {
	item1 := BPitem{89, "45"}
	fmt.Println("b+tree", item1.key, item1.val.(string))

	item2 := BPitem{89, 456}
	fmt.Println("b+tree", item2.key, item2.val.(int))

	item3 := BPitem{89, map[string]string{"name1": "gaofeng", "name2": "yangyang"}}
	m := item3.val.(map[string]string)
	fmt.Println("b+tree", item3.key, m)
}

10、 不知道类型时,如何转换? 用switch case判断

func f1()  {
	var a = f2()

	fmt.Println(a)

	switch v := a.(type) {
	case int:
		fmt.Println("int")
	default:
		fmt.Println("ggg:", v, a)
	}
}
func f2() interface{} {
	return "5"
}

11、go https server

Go和HTTPS - Go语言中文网 - Golang中文社区

package main

import "fmt"
import "net/http"

func hello1(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "\nhello,%s,%s,%s", r.Method, r.UserAgent(), r.Header["Content-Type"])
}
func hello2(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "\nhello2222")
}
func main() {
	http.HandleFunc("/hello1", hello1)
	http.HandleFunc("/hello2", hello2)
	//	http.ListenAndServe(":9090", nil)
	http.ListenAndServeTLS(":9090", "server.crt", "server.key", nil)
}

openssl genrsa -out server.key 2048

openssl req -new -x509 -key server.key -out server.crt -days 365

13、上传文件

https://www.jianshu.com/p/981623bb8dd6

14、go redis

使用的是github.com/garyburd/redigo/redis 这个第三方redis客户端库

本次实验,使用gopath机制

go get github.com/garyburd/redigo/redis将这个库下载到G:\gaofeng\go3\src
(gopath为G:\gaofeng\go3\)


package main

import (
	"fmt"

	"github.com/garyburd/redigo/redis"
)

func main() {
	c, err := redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer c.Close()

	v, err := c.Do("SET", "name", "red")
	fmt.Println("set", v, err)

	v, err = redis.String(c.Do("GET", "a"))
	fmt.Println("get", v, err)

	vv, err2 := redis.Values(c.Do("lrange", "pp", "0", "100")) //list
	fmt.Println("lrange", len(vv), err2)
	fmt.Printf("v1 type:%T\n", vv)
	for i, v := range vv {
		fmt.Println(i, string(v.([]byte)))
	}

	vv, err2 = redis.Values(c.Do("keys", "*"))
	for i, v := range vv {
		fmt.Println(i, string(v.([]byte)))
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值