一、描述
此文章是对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
}
函数变量也可以这样定义:
func add(x ,y int) int {
return x + y
}
函数可以返回多个参数,
func main() {
c,d:=back("1","2");
fmt.Print(c,d)
}
func back(a ,b string) (string,string) {
return a,b
}
函数的返回值也可以设置变量名字,并且在函数中进行赋值
func main() {
fmt.Print(sum(3))
}
func sum(num int) (x,y int) {
x = num * 4 / 9
y = num * 4
return
}
//切割处理,根据指定的个数,从字符串的个数位置开始切割
str := "hellow";
s := str[2:]
fmt.Print(s) //结果:llow
` 括起的字符串为Raw字符串,即字符串在代码中的形式就是打印时的形式,它没有字符转义,换行也将原样输出。例如本例中会输出:
m := `hello
world`
fmt.Print(m)
//结果:
hello
world
标签跳转(标签名是大小写敏感的。)
i := 0
Here: //这行的第一个词,以冒号结束作为标签
println(i)
i++
goto Here //跳转到Here去,从Here的位置重新开始执行,产生循环
对集合进行遍历键值
//对slice或者map进行遍历,返回键和值,j就是集合
for k,v:=range j {
fmt.Println("map's key:",k)
fmt.Println("map's val:",v)
}
Switch
//switch默认是添加break的,如果想继续往下执行,就加fallthrough关键字,switch能够判断的类型很多
i := 1
switch i {
case 1:
fmt.Print(1)
fallthrough
case 2:
fmt.Print(2)
fallthrough
}
指针
//简单的一个函数,实现了参数+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
}
匿名类
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")
}
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
}
五、Web服务端搭建
注意: 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)
}
}
登陆示例
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进行解析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()
八、数据库操作
数据库教程: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)
}
九、Cookie 和 Session
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)
十、文件操作
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") //写入字符串
}
十一、字符串处理
//判断字符串是否存在
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"))
九、系统函数
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
十、注意事项
1.下面的两个声明是一样的, := 可以替代var的声明,如果没有:就直接一个=,就是赋值了,左边被赋值的变量必须是已经声明过的对象
var a,b int = 1,2 //这个是声明a和b
a,b := 1,2 //这个也是声明a,b
2.在声明方法或者变量的时候,修饰符private和public的区分在于你是否大小写,大写的话就是Public,小写就是P
3.如果你想要调试Debug项目的话,第一次会没办法debug,你需要再创建一个go文件才可以进行调试,这是个Bug吧?
4.如果遇到把对象转Json字符串的时候,对象中的字段的头字母必须是大写,不然没有办法转换,并且最后用string(json)转换输出
5.在一个类中想要引用其他包里类中的方法或者属性,需要引入进来,但是试了下,发现其他包的对象根本打不出来?只有在本类中创建的类才识别的到?
解决:你需要把你的项目全路径,设置到环境变量的GoPath上,这样就能够识别到其他包下的方法和属性等。
十一、学习资料
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}}
十二、总结
下面的两段代码,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)
如果不自行注册对应页面的对应服务,他将不会相应。