Go

337 阅读9分钟

##一、描述
此文章是对Go的说明以及使用进行详细的记录,并且记录学习当中有遇到的问题。

##二、环境配置
Go的下载地址:https://golang.org/dl/

Go在IDEA的插件配置:http://jingyan.baidu.com/article/f25ef25446109c482c1b821d.html

Go的环境配置:

export GOROOT=/usr/local/go
export GOPATH=$HOME/goworkspace
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

第一个Go的目录 第二个是Go的工作目录 第三个直接复制把

go env 可查看目前的go的环境变量   这go就可以执行了, 下面还要配置一个GOPATH环境变量,是工作目录。   根据约定,GOPATH下需要建立3个目录: bin 存储编译后的可执行文件 pkg 存放编译后生成的包文件 src 存放项目的源码  我把GOPATH建立在/Users/Demon/Desktop/gowork   vi ~/.bash_profile


##三、变量定义

const age int = 5 //常量定义

//iota默认是0,如果多次赋值iota,iota会递增,如果遇到const会让iota归0
func main() {
	const (
		a = iota // a = 0
		b = iota // b = 1
		c = iota // c = 2
		d = iota // d = 3
	)
	fmt.Print(a)
	fmt.Print(b)
	fmt.Print(c)
	fmt.Print(d)

}
//指定个数的数组定义
var array [10]int ;//第一种
array[0] = 5

array := [10]int{1,2,3}//第二种

//动态数组定义,不指定个数
var slice []int;//第一种
slice = []int{1,2,3}

slice := []byte {'a', 'b', 'c', 'd'}//第二种

//获取数组中的值
sun := [8]int {1,2,3,4,5,6,7,8}
a := sun[2:4] //从数组中获取指定的索引中的数值,a = 3 , 4

ar[:n]等价于ar[0:n]


//创建Map 第一个int是key,第二个是value
numbers := make(map[string]int)
numbers["1"] = 1  //赋值
numbers["2"] = 2 //赋值
numbers["3"] = 3
fmt.Println("第三个数字是: ", numbers["1"]) // 读取数据

	
image := map[string]int{"one":1,"two":2}
// map有两个返回值,第二个返回值,如果不存在key,那么ok为false,如果存在ok为true
result,ok := image["two"]
if ok{
	fmt.Print("存在",result,"啊")
}else {
	fmt.Print("不存在")
}
delete(image,"two") //删除对应集合的对应键的值

//ap也是一种引用类型,如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变
m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut"  // 现在m["hello"]的值已经是Salut了

##四、函数
```

func main() { fmt.Print("hehe",add(2,3)) }

func add(x int ,y int) int { return x + y }

</br>
函数变量也可以这样定义:

func add(x ,y int) int { return x + y }

</br>
函数可以返回多个参数,

func main() { c,d:=back("1","2"); fmt.Print(c,d) }

func back(a ,b string) (string,string) { return a,b }

</br>
函数的返回值也可以设置变量名字,并且在函数中进行赋值

func main() { fmt.Print(sum(3)) }

func sum(num int) (x,y int) { x = num * 4 / 9 y = num * 4 return }

</br>
//切割处理,根据指定的个数,从字符串的个数位置开始切割

str := "hellow"; s := str[2:] fmt.Print(s) //结果:llow

</br>
` 括起的字符串为Raw字符串,即字符串在代码中的形式就是打印时的形式,它没有字符转义,换行也将原样输出。例如本例中会输出:

m := hello world fmt.Print(m)

//结果: hello world

</br>
标签跳转(标签名是大小写敏感的。)

i := 0 Here: //这行的第一个词,以冒号结束作为标签 println(i) i++ goto Here //跳转到Here去,从Here的位置重新开始执行,产生循环

</br>
对集合进行遍历键值

//对slice或者map进行遍历,返回键和值,j就是集合 for k,v:=range j { fmt.Println("map's key:",k) fmt.Println("map's val:",v) }

</br>
Switch

//switch默认是添加break的,如果想继续往下执行,就加fallthrough关键字,switch能够判断的类型很多

i := 1 switch i { case 1: fmt.Print(1) fallthrough case 2: fmt.Print(2) fallthrough }


</br>
指针

//简单的一个函数,实现了参数+1的操作 x1 := add1(&x) // 调用 add1(&x) 传x的地址

func add1(a *int) int { // 请注意, *a = *a+1 // 修改了a的值 return *a // 返回新值 }


函数结果之前必定调用Defer

//在defer后指定的函数会在函数退出前调用 func ReadWrite() bool { file.Open("file") defer file.Close() if failureX { return false } if failureY { return false } return true }


方法传参

//创建一个func(int)这种格式的方法体,能够代表这种格式的方法,比如add()和delete() type addOrDelete func(int) string

func main() { //传入add方法,add方法不需要加() fmt.Print(getContent(2, add)) }

func add(a int) string { return strconv.Itoa(a+1) }

func delete(b int) string { return strconv.Itoa(b+1) }

//传入addOrDelete类型的方法 func getContent(a int, method addOrDelete) string { return method(a) //利用传入的方法返回数据 }


Struct对象

type user struct { Name string json:name Age int json:age }

func main() { //第一种声明 var user01 user user01.age = 12 user01.name = "dsf" //第二种 user02 := user{name:"俊文", age:14} //第三种 user03 := user{"俊文", 12} //判断第二个和第三个对象的年龄对比 if max(user02, user03) { fmt.Print("第一个大于第二个") } }

func max(a, b user) bool { return a.age > b.age }


</br>
匿名类

type student struct { studentName string studentage int }

type user struct { student //student类作为参数,user类可以直接只用student内的字段属性 name string age int }

func main() { //如果在声明user的时候就传入对象,则需要把他的所有参数都填满,不然会报错 myuser := user{student{studentName:"studentName", studentage:12}, "name", 21} fmt.Print(myuser.studentName) fmt.Print(myuser.studentage, "\n") fmt.Print(myuser.name) fmt.Print(myuser.age, "\n") }

</br>
Struct方法的定义

type student struct { studentName string studentage int }

type user struct { name string age int }

func (stu student)getName() string { return stu.studentName }

func (use user)getName() string { return use.name }

</br>

##五、Web服务端搭建
</br>

>注意: r.ParseForm()必须要加,不然Post或者Get取不到数据

http包建立Web服务器
func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()  //解析参数,默认是不会解析的
    fmt.Println(r.Form)  //这些信息是输出到服务器端的打印信息
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["url_long"])
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, "Hello astaxie!") //这个写入到w的是输出到客户端的
}

func main() {
    http.HandleFunc("/", sayhelloName) //设置访问的路由
    err := http.ListenAndServe(":9090", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

</br>
登陆示例

![](http://upload-images.jianshu.io/upload_images/2650372-ae38064bdf230415.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

func login(w http.ResponseWriter, r *http.Request) { method := r.Method if method == "GET" { //加载指定的页面进行展示,展示只需要t.Execute(w, nil) , err是获取这个文件如果出错了,会返回error t, err := template.ParseFiles("login.html") log.Println(t.Execute(w, nil)) } else { r.ParseForm() //解析Post或者Get的数据,必须加上不然没数据 fmt.Fprint(w,"username:", r.Form["username"]) fmt.Fprint(w,"password:", r.Form["password"]) } }

func main() { //指定请求当前目录的login接口 http.HandleFunc("/login", login) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }

//Html

用户名: 密码: ```

##六、Json解析与转换

####转换

1 对象转换Json

var s User
b ,e := json.Marshal(s) //User对象转换Json字符串
if e != nil{
	fmt.Print("有错误")
	return
}
fmt.Println(string(b)) //输出 {"Name":"俊文","Age":"23"}

2 Json转换成对象

result, err := ioutil.ReadAll(r.Body) //读取客户端上传的RequestBody 返回byte[] ,err
		if err != nil {
			fmt.Fprint(w,"错误")
		}else{
			var s User
			json.Unmarshal(result, &s) //把Json字符串转换成User对象
			fmt.Print(s.Name) //输出 
		}

####解析 可以用**[go-simplejson](https://github.com/bitly/go-simplejson)**进行解析Json字符串。 ``` js, err := NewJson([]byte(`{ "test": { "array": [1, "2", 3], "int": 10, "float": 5.150, "bignum": 9223372036854775807, "string": "simplejson", "bool": true } }`))
arr, _ := js.Get("test").Get("array").Array()



</br>



##八、数据库操作
</br>

数据库教程:https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/05.2.md

MySQL驱动下载示例

//下载对应的驱动 go get github.com/graphql-go/graphql

//安装对应的驱动 go install github.com/graphql-go/graphql

//导入驱动运用,如果还是红色,请重启IDE import ( _ "github.com/go-sql-driver/mysql" //这个是MySql的驱动 "database/sql" )


MySql

//连接MySql数据库 db,_ := sql.Open("mysql","root:root@/jun_data")

//插入数据 result ,_ := db.Exec("insert into user values(null,?,?)","junwen","21") //执行Insert插入语句,参数一是sql,参数二是对应的数值 fmt.Print(result.LastInsertId())

//删除数据 result ,_ := db.Exec("delete from user where _id=?",1) //执行删除语句 fmt.Print(result.RowsAffected()) //输出受影响的行数

//更新数据 result ,_ := db.Exec("update user set username=? where _id=?","哈哈",8) //执行更新语句 fmt.Print(result.RowsAffected())

//查找数据 query , _ :=db.Query("select * from USER ") // 执行查询语句

for query.Next(){ var id int var name string var age string query.Scan(&id,&name,&age) fmt.Println("id:",id) fmt.Println("name:",name) fmt.Println("age:",age) }

</br>
##九、Cookie 和 Session
</br>
Cookie

//设置Cookie cook := http.Cookie{Name:"mycook",Value:"junwen",Expires:time.Now().Add(60)} http.SetCookie(w,&cook)

//取Cookie cookie,_:= r.Cookie("mycook") fmt.Print(cookie.Value)

</br>
##十、文件操作
</br>

func main() { os.Mkdir("astaxie", 0777) //创建一个0777权限的文件夹 os.MkdirAll("astaxie/test1/test2", 0777) //根据路径创建文件夹,包括路径中不存在的文件夹一并创建 err := os.Remove("astaxie") //删除文件夹 if err != nil { fmt.Println(err) } os.RemoveAll("astaxie") //删除所有文件夹,包括子文件夹

//判断文件是否存在,如果err为空,就存在 fileInfo,err := os.Stat("junwen.txt")

//打开文件进行写入文件,1 文件名 2 模式:追加还是覆盖等 3 权限 file,_ := os.OpenFile("junwen123.txt",os.O_APPEND,0666) file.WriteString("waerwaeraser") //写入字符串 }


##十一、字符串处理
</br>

//判断字符串是否存在 strings.Contains("seafood", "foo")

//处理stirng[]类型,追加字符串 s := []string{"foo", "bar", "baz"} fmt.Println(strings.Join(s, ", ")) //输出:foo, bar, baz

//求出ken在字符串中的index索引地址 fmt.Println(strings.Index("chicken", "ken"))


##九、系统函数
</br>

strconv.Atoi(a) //String转int类型,返回转换的结果bool和结果int strconv.Itoa(a) //Int转String,返回成功后的string类型 fmt.Printf("v is of type %T\n",v) //可以打印v的类型,注意是printf 这个F

##十、注意事项
</br>

1.下面的两个声明是一样的, := 可以替代var的声明,如果没有:就直接一个=,就是赋值了,左边被赋值的变量必须是已经声明过的对象

var a,b int = 1,2 //这个是声明a和b

a,b := 1,2 //这个也是声明a,b

</br>
2.在声明方法或者变量的时候,修饰符private和public的区分在于你是否大小写,大写的话就是Public,小写就是P

3.如果你想要调试Debug项目的话,第一次会没办法debug,你需要再创建一个go文件才可以进行调试,这是个Bug吧?

4.如果遇到把对象转Json字符串的时候,对象中的字段的头字母必须是大写,不然没有办法转换,并且最后用string(json)转换输出

5.在一个类中想要引用其他包里类中的方法或者属性,需要引入进来,但是试了下,发现其他包的对象根本打不出来?只有在本类中创建的类才识别的到?

解决:你需要把你的项目全路径,设置到环境变量的GoPath上,这样就能够识别到其他包下的方法和属性等。
##十一、学习资料
</br>

https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/preface.md

https://github.com/graphql-go/graphql

http://git.oschina.net/Lemon19950301/APIJSON

https://my.oschina.net/u/943306/blog/151293

https://my.oschina.net/liudiwu/blog/305014?p={{currentPage-1}}

##十二、总结
</br>
下面的两段代码,http.ListenAndServe(":8080",nil)这一段就像是监听了一栋房子,:8080就是门牌号,第二个参数就是指挥官,所有的参战人员进攻都需要通过指挥官,但是指挥官一个人觉得太累,这里用了nil,就用了系统默认的指挥官。

http.HandleFunc这一段就是在注册不同的行动任务具体实施该怎么实施,第一个参数就是任务,第二个参数就是具体的行动。可以自行定义方法传入,也可以像下面这样,匿名的

http.HandleFunc("/sng", func(w http.ResponseWriter,r *http.Request) { fmt.Fprint(w,"sng") }) http.ListenAndServe(":8080",nil)

如果不自行注册对应页面的对应服务,他将不会相应。

![](https://upload-images.jianshu.io/upload_images/2650372-995208295888e296.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)