Go

一、描述



此文章是对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)
        }
    }



登陆示例

Go_第1张图片
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)

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

Go_第2张图片

你可能感兴趣的:(Go)