0


mac安装Golang开发环境及快速入门

一、Mac brew 安装go环境

1.1 安装步骤

1)终端输入,也可以指定下载go版本

brew install go

2)查看golang当前版本

go version

3)查看当前golang环境 执行

go env

1.2 设置GOPATH 及环境变量

1)GOPATH 是工作目录,工作空间目录 go_project 就是一个目录,其中包含三个子目录:

  • src 目录包含Go的源文件,它们被组织成包(每个目录都对应一个包),
  • pkg 目录包含包对象,
  • bin 目录包含可执行命令。

如下图:

​2) 终端输入

vim .zshrc

添加:

GOPATH 后面加你自己的工作空间,这里是我自己建立的go_project

export GOPATH="/Users/mima6ge0/Documents/yanhan_practice/go_project"

export PATH = $PATH:$GOPATH/bin

执行

source ~/.zshrc 
生效,使用go env查看是否修改成功

1.3 编写第一个go程序

1)新建hellow.go文件

package main

import "fmt"

func main() {
    fmt.Println("hello, world")
}

2)进入文件所在目录,执行go run hellow.go,成功,如下图

二、快速入门

2.1 快速入门需求

  • 具备1种后端编程语言开发经验(C/C++/Java/Python/PHP)
  • 具备基本的网络编程能力和并发思想
  • 了解计算机基本体系结构
  • 了解Linux基础知识

2.2 go学习(自用)

2.2.1 go基础程序

package main //程序的包名
// main函数
//多个文件导入
import (
    "fmt"
    "time"
)

func main() { //函数的"{"必须和函数名在一行,换到下一行就是语法错误,强制代码风格
    fmt.Println("hellow Go!")
    //go语言不需要";",可有可无
    time.Sleep(10 * time.Second)
}

2.2.2 变量声明

package main
/*
变量的声明方法
 */
import "fmt"
//全局变量,冒等方法不支持全局,其他的都可以
var A int = 100
func main() {
    //声明变量默认值是0
    var a int
    fmt.Println("a = ", a)
    fmt.Printf("type of a = %T\n", a)
    //声明变量,初始化
    var b int = 100
    fmt.Println("b = ", b)
    fmt.Printf("type of v = %T\n", b)
    //初始化可以省去变量类型,通过值去匹配变量的树枝类型
    var c = 100
    fmt.Println("c = ", c)
    fmt.Printf("type of c = %T\n", c)
    //字符串
    var d string = "dasda"
    fmt.Println("d = ", d)
    fmt.Printf("type of d = %T\n", d)
    //最常用方法:冒等,省略var,直接自动匹配,":="初始化加赋值,函数内部使用
    e := 3213.432
    fmt.Println("e = ", e)
    fmt.Printf("type of e = %T\n", e)

    fmt.Println("A = ", A)
    fmt.Printf("type of A = %T\n", A)

    //声明多个变量
    var x, y int = 100, 100
    fmt.Println("x = ", x, ", y = ", y)
    var m, n = 100, "88090"
    n = "kjuhku"
    fmt.Println("m = ", m, ", n = ", n)
    //多行多变量声明
    var (
        xx int = 121
        zz bool = true
    )
    fmt.Println("xx = ", xx, ", zz = ", zz)
}

2.2.3 常量和枚举

package main

import "fmt"

//const 可以定义枚举类型
const (
    //可以在const里面添加一个关键字 iota,每行的iota都会累加1,第一行的iota的默认值是0
    BEIJING = 10 * iota // iota = 0
    SHANGHAI        //iota = 10
    SHENZHEN        //iota = 20
)

const (
    a, b = iota + 1, iota + 2 //iota = 0, a = 1, b = 2
    c, d                      //iota = 1, c = 2, d = 3
    e, f                      //iota = 2, e = 3, f = 4
    g, h = iota * 2, iota * 3 //iota = 3, g = 6, h = 9
    i, k                      //iota = 4, i = 8, k = 12
)

func main() {
    //常量,只读,不允许修改
    const a int = 100
    fmt.Println("a = ", a)
    fmt.Println("BEIJING = ", BEIJING)
    fmt.Println("SHANGHAI = ", SHANGHAI)
    fmt.Println("SHENZHEN = ", SHENZHEN)

    fmt.Println("a = ", a, "b = ", b)
    fmt.Println("c = ", c, "d = ", d)
    fmt.Println("e = ", e, "f = ", f)
    fmt.Println("g = ", g, "h = ", h)
    fmt.Println("i = ", i, "k = ", k)
    //iota只能在const里面使用,var里面不可以
    

}

2.2.4 函数与多种返回值

package main

import "fmt"

//返回一个值,匿名
func foo1(a string, b int) int {
    fmt.Println("a = ", a)
    fmt.Println("b = ", b)
    c := 100
    return c
}

//返回多个值,匿名
func foo2(a string, b int) (int, int) {
    fmt.Println("--------foo2----------")
    fmt.Println("a = ", a)
    fmt.Println("b = ", b)
    return 888, 9999
}

//返回多个返回值,有形参名称
func foo3(a string, b int) (r1 int, r2 int) {
    fmt.Println("--------foo3----------")
    fmt.Println("a = ", a)
    fmt.Println("b = ", b)

    r1 = 1000
    r2 = 100000
    return 
}

func foo4(a string, b int) (r1, r2 int) {
    fmt.Println("--------foo4----------")
    fmt.Println("a = ", a)
    fmt.Println("b = ", b)

    //r1, r2属于foo3的形参,初始化默认的值是0,作用域空间是整个foo4函数{}的整体
    fmt.Println("未赋值:r1 = ", r1)
    fmt.Println("未赋值:r2 = ", r2)
    r1 = 1000
    r2 = 100000
    return 
}

func main() {
    c := foo1("func1", 1)
    fmt.Println("c = ", c)
    ret1, ret2 := foo2("func2", 2)
    fmt.Println("ret1 = ", ret1)
    fmt.Println("ret2 = ", ret2)

    r1, r2 := foo3("func3", 3)
    fmt.Println("r1 = ", r1)
    fmt.Println("r2 = ", r2)

    r1, r2 = foo4("func4", 4)
    fmt.Println("r1 = ", r1)
    fmt.Println("r2 = ", r2)

}

2.2.5 init函数与import导包

文件目录树状图

lib1.go 代码:

package lib1

import "fmt"

//当前lib1包提供的API
//首字母大写的话代表当前接口对外开放,首字母小写只能在该文件下使用
func Lib1Test () {
    fmt.Println("Lib1Test() ...")
}

func init () {
    fmt.Println("lib1 init ...")
}

lib2.go 代码:

package lib2

import "fmt"

//当前lib2包提供的API
func Lib2Test () {
    fmt.Println("Lib2Test() ...")
}

func init () {
    fmt.Println("lib2 init ...")
}

main.go代码:

package main

//需要在GOPATH下
import (
    "GolangStudy/5_init/lib1"
    "GolangStudy/5_init/lib2"
)

func main () {
    lib1.Lib1Test()
    lib2.Lib2Test()
}

2.2.6 import匿名、别名导包

基于2.2.5的代码

package main

//需要在GOPATH下,go语言语法比较严格,导入必须使用
import (
    // _ 匿名导包,导入但是不使用,不会报错
    _ "GolangStudy/5_init/lib1"

    //mylib2是lib2的别名
    //mylib2 "GolangStudy/5_init/lib2"

    //可以不写包名直接使用Lib2Test(),把方法导入当前main包里面,不建议使用,如果有重名函数,会出现问题
    . "GolangStudy/5_init/lib2"
)

func main () {
    //lib1.Lib1Test()

    //mylib2.Lib2Test()

    Lib2Test() 
}

总结:

2.2.7 defer调用顺序

package main
/*
defer的执行顺序是在函数体全部执行完以后和结束之前,
多个defer语句是压栈的,defer在return后面执行
*/
import "fmt"

func func1() {
    fmt.Println("A")
}

func func2() {
    fmt.Println("B")
}

func func3() {
    fmt.Println("C")
}

func main () {
    defer func1()
    defer func2()
    defer func3()
}

2.2.8 数组的表示和动态数组 slice

1)固定长度数组表示,遍历等(不建议,不常用)

package main
import "fmt"

//不建议使用,可以使用动态数组
func printArray (array [4]int){
    //值拷贝
    fmt.Println("---------------输出函数--------------")
    for i := 0; i < len(array); i++ {
        fmt.Println("array2_value = ", array[i])
    }

    //如果要对数组的值进行修改,下面这种传参是改不了的
    // array[0] = 10000
}
func main () {
    // 固定长度数组
    var array1 [10]int
    for i := 0; i < len(array1); i++ {
        fmt.Println("array1_value = ", array1[i])
    }
    array2 := [10]int{1, 2, 4, 5}
    array3 := [4]int{1, 2, 4, 5}
    for index, value := range array2 {
        fmt.Println("array2_index = ", index, "array2_value = ", value)
    }

    printArray(array3)

    // 打印数组类型
    fmt.Printf("array1 type : %T\n", array1)
    fmt.Printf("array2 type : %T\n", array2)
    fmt.Printf("array3 type : %T\n", array3)

}

2)动态数组,切片,slice

package main
import "fmt"

func printArray(array []int) {
    // 引用拷贝,传递的是数组指针,所以array[0]会被修改为100
    array[0] = 100
    // _ 表示匿名的变量,不被使用也不会发生问题
    for _, value := range array {
        fmt.Println("value = ", value)
    }
}
func main() {
    // 动态数组,切片,slice
    array := []int{1, 2, 3, 4}
    //查看array的类型
    fmt.Printf("array type : %T\n", array)

    printArray(array)

}

3)slice四种定义声明方式

package main

import (
    "fmt"

)
func main() {

    // 声明slice1是一个切片,并且初始化,长度是3,默认值是1, 2, 3
    // slice1 := []int{1, 2, 3}

    // 声明slice1是一个切片,但是没有分配空间,len = 0,value = []
    // var slice1 []int 
    // 可以通过make来开辟几个空间,这时候len = 3,value = [0, 0, 0]
    // slice1 = make([]int, 3)

    // 声明slice1是一个切片,通过make来开辟3空间,这时候len = 3,value = [0, 0, 0]
    // var slice1 []int = make([]int, 3)

    // 声明slice1是一个切片,通过make来开辟3空间,这时候len = 3,value = [0, 0, 0],通过:=推测出他是一个切片
    slice1 := make([] int, 3)

    fmt.Printf("len = %d , value = %v\n", len(slice1), slice1)

    // 判断一个切片是否为空
    if slice1 == nil {
        fmt.Println("slice1 is null!")
    } else {
        fmt.Println("slice2 is not null!!")
    }
}

4)slice切片追加与截取

package main

import "fmt"
func main () {
    // 切片中len和cap是不同的
    var numbers = make([] int, 3, 5) // len = 3, cap容量 = 5
    fmt.Printf("len = %d, cap = %d, value = %v\n", len(numbers), cap(numbers), numbers)
    //追加一个元素7
    numbers = append(numbers, 7)
    fmt.Printf("len = %d, cap = %d, value = %v\n", len(numbers), cap(numbers), numbers)
    numbers = append(numbers, 8)
    // 当追加元素时,容量已满,则自动扩充为原来一开始定义的cap的二倍,扩充为10
    numbers = append(numbers, 9)
    fmt.Printf("len = %d, cap = %d, value = %v\n", len(numbers), cap(numbers), numbers)

    // 没有定义容量的情况,但是在容量已满的情况下追加元素,直接扩充为len的二倍
    var numbers2 = make([] int, 3)
    fmt.Printf("len = %d, cap = %d, value = %v\n", len(numbers2), cap(numbers2), numbers2)
    numbers2 = append(numbers2, 4)
    fmt.Printf("len = %d, cap = %d, value = %v\n", len(numbers2), cap(numbers2), numbers2)

    // slice切片
    s := [] int{1, 2, 3, 4}
    s1 := s[0:2] //s1是s中的索引在[0, 2)区间的元素,和python类似
    fmt.Println("s1 = ", s1)
    s2 := s[1:] //s1是s中的索引在[1, len(s))区间的元素,和python类似
    fmt.Println("s2 = ", s2)
    //如若修改s1里面的元素,s也会随之改变,因为这种切片相当于指针指向了s,所以改s1值,s和s1会一起发生改变(浅拷贝)
    s1[0] = 20000
    fmt.Println("s = ", s)

    // go提供了copy函数,切片的时候只将值复制过来,(深拷贝)
    s3 := make([] int, 3) //[0, 0, 0]
    // 将s2的值依次拷贝到s3中
    copy(s3, s2)
    fmt.Println("s3 = ", s3)
}

2.2.9 map的声明使用

1)map的声明

package main

import "fmt"
func main() {
    // 第一种声明方式
    var map1 map[string]string
    if map1 == nil {
        fmt.Println("map1是一个空map!!")
    }
    // 使用前,需要通过make来给map分配数据空间
    map1 = make(map[string]string, 3)
    map1["one"] = "java"
    map1["two"] = "php"
    map1["three"] = "python"
    fmt.Println("map1 = ", map1)

    // 第二种声明方式,直接:=
    map2 := make(map[int]string)
    map2[1] = "baidu"
    map2[2] = "tengxun"
    map2[3] = "ali"
    fmt.Println("map2 = ", map2)

    // 第三种声明方式,一般带有初始化的map用这种方式
    map3 := map[string]string{
        "王八": "绿豆",
        "傻子": "小丑",
    }
    fmt.Println("map3 = ", map3)
}

2)map的使用

package main

import (
    "fmt"
)

func printMap (city_map map[string]string) {
    // 遍历
    for key, value := range city_map {
        fmt.Println("key = ", key, ", value = ", value)
    }
}

func changeMap (city_map map[string]string) {
    // city_map是一个引用传递,传递过来是地址,可以修改city_map
    city_map["UK"] = "london"
}
func main() {
    cityMap := make(map[string]string)
    cityMap["china"] = "beijing"
    cityMap["USA"] = "DC"
    
    
    printMap(cityMap)

    // 删除
    delete(cityMap, "china")
    fmt.Println("-----------删除后---------------")
    printMap(cityMap)

    // 修改
    cityMap["USA"] = "london"
    fmt.Println("-----------修改后---------------")
    printMap(cityMap)

    // 增加
    cityMap["china"] = "beijing"
    fmt.Println("-----------增加后---------------")
    printMap(cityMap)

    changeMap(cityMap)
    fmt.Println("-----------函数增加后---------------")
    printMap(cityMap)

}

2.2.10 面向对象

1)结构体的使用

package main

import "fmt"

// 声明一种数据类型,myint是int的别名
type myint int
// 声明结构体
type Book struct{
    title string
    auth string
}

func changeBook (book Book) {
    // 传递了一个book的副本
    book.title = "三体"
}

func changeBook2 (book *Book) {
    // 指针传递
    book.title = "生死疲劳"
}

func main () {
    var a myint = 232
    fmt.Println("a = ", a)
    fmt.Printf("type of a is %T\n", a)

    var book1 Book
    book1.title = "活着"
    book1.auth = "余华"
    fmt.Printf("%v\n", book1)

    changeBook(book1)
    // 使用上面changeBook,修改值并没有成功
    fmt.Printf("%v\n", book1)

    // 参数是地址,所以要加"&"
    changeBook2(&book1)
    fmt.Printf("%v\n", book1)

}

2)面向对象类的表示

A、封装

package main

import "fmt"

// 类名、属性名、方法名、首字母大写代表其他包可以访问,首字母小写代表私有,只有本包内可以使用
type Hero struct {
    Name string
    Ad int
    Level int
}

// 如果不写*Hero,这里传进去的一个副本,如果想在函数内对其进行修改,要用*Hero
func (this Hero) Show() {
    // 副本
    fmt.Println("Name : ", this.Name)
    fmt.Println("Ad : ", this.Ad)
    fmt.Println("Level : ", this.Level)
}

func (this Hero) GetName() string {
    return this.Name
}

func (this *Hero) SetName(name string) {
    // 这样才是当前对象
    this.Name = name
}

func main() {
    hero := Hero{ Name: "freezing", Ad: 33, Level: 1}
    hero.Show()
    hero.SetName("rebecca")
    hero.Show()

}

B、继承

package main

import "fmt"

type Human struct {
    name string
    age int
}

func (this *Human) Walk() {
    fmt.Println("Human walk .....")
}

func (this *Human) Eat() {
    fmt.Println("Human eat .....")
}

type Superhero struct {
    // 继承Human写法
    Human
    level int
}

// 重定义(方法重写)父类方法
func (this *Superhero) Eat() {
    fmt.Println("Superhero eat .....")
}

// 子类的新方法
func (this *Superhero) Fly() {
    fmt.Println("Superhero fly .....")
}

func main() {
    human := Human{"freezing", 20}
    human.Eat()
    human.Walk()
    superhero := Superhero{Human{"rebecca", 30}, 1}
    superhero.Walk() // 父类方法
    superhero.Eat()  // 子类方法
    superhero.Fly()  // 子类方法
    // 另外一种初始化对象的方法
    var s Superhero
    s.age = 24
    s.level  = 1
    s.name = "cookie wan"
}

2.2.10 json

1)json.Unmarshal反序列化,将json结构解析,如果解析过程中发生错误,

json.Unmarshal

会返回一个非空的错误对象。

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    jsonData := []byte(`{"name":"John", "age":30}`)
    var person Person
    // 用于将 JSON 格式的数据解析(反序列化)为 Go 对象
    err := json.Unmarshal(jsonData, &person)
    if err != nil {
        fmt.Println("解析 JSON 失败:", err)
        return
    }
    // John 30
    fmt.Println(person.Name, person.Age)
}

三、debug

3.1 go: cannot run *_test.go files

背景:将go文件命名成array_test.go报错*go: cannot run _test.go files

原因:_test.go 是golang专用的测试文件

解决:改名

3.2 深拷贝(copy)和浅拷贝(slice切片)

https://blog.csdn.net/weixin_45440484/article/details/131740125

3.3 引用传递

引用传递是一种变量传递的方式,它不是直接传递变量的值,而是传递变量的内存地址(引用)。在引用传递中,被调用函数可以通过引用修改原始变量的值。

标签: macos golang

本文转载自: https://blog.csdn.net/weixin_45440484/article/details/131692655
版权归原作者 Rebecca.Yan 所有, 如有侵权,请联系我们删除。

“mac安装Golang开发环境及快速入门”的评论:

还没有评论