golang开发环境搭建与踩坑记录

文章目录

一、安装下载

1、go环境

下载地址:https://go.dev/dl/

或者:https://golang.google.cn/dl/

windows直接下载msi文件安装即可。

linux下载之后,进行解压+环境变量设置:

bash 复制代码
# 下载
wget https://go.dev/dl/go1.22.5.linux-amd64.tar.gz
# 解压
tar -zxvf go1.22.5.linux-amd64.tar.gz
# 进入到go的解压路径
/root/go/go/bin

# 临时环境变量,关闭控制台就失效了
export PATH=$PATH:/root/go/go/bin
# 编辑 ~/.bash_profile 或者 /etc/profile,添加
export PATH=$PATH:/root/go/go/bin
# 环境变量生效
source ~/.bash_profile
# 或
source /etc/profile

# 验证
[root@localhost ~]# go version
go version go1.22.5 linux/amd64

2、ide

GoLand:https://www.jetbrains.com/go/

二、基本使用

1、运行

bash 复制代码
# 直接运行
go run hello.go
# 编译为可执行文件
go build hello.go 

2、结构体与方法函数指针

go 复制代码
package main

import "fmt"

type Books struct {
	/*首字母大写相当于 public。
 	首字母小写相当于 private。
	这个 public 和 private 是相对于包(go 文件首行的 package 后面跟的包名)来说的。

	当要将结构体对象转换为 JSON 时,对象中的属性首字母必须是大写,才能正常转换为 JSON。
	*/
   title string
   author string
   subject string
   book_id int
}

func main() {

	// 创建一个新的结构体
	fmt.Println(Books{"Go 语言", "www.4399.com", "Go 语言教程", 6495407})

	// 也可以使用 key => value 格式
	fmt.Println(Books{title: "Go 语言", author: "www.4399.com", subject: "Go 语言教程", book_id: 6495407})

	// 忽略的字段为 0 或 空
	fmt.Println(Books{title: "Go 语言", author: "www.4399.com"})

   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.4399.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.4399.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}

func printBook( book Books ) {
	fmt.Printf( "Book title : %s\n", book.title)
	fmt.Printf( "Book author : %s\n", book.author)
	fmt.Printf( "Book subject : %s\n", book.subject)
	fmt.Printf( "Book book_id : %d\n", book.book_id)
 }
go 复制代码
package main

import (
   "fmt"  
)

/* 定义结构体 */
type Circle struct {
  radius float64
}


func main()  { 
   var c Circle
   fmt.Println(c.radius)
   c.radius = 10.00

   // 方法返回值用参数接收 
   area := c.getArea()
   fmt.Println()
   c.changeRadius(20)
   fmt.Println(c.radius)
   change(&c, 30)
   fmt.Println(c.radius)
}
func (c Circle) getArea() float64  {
   return c.radius * c.radius
}
// 注意如果想要更改成功c的值,这里需要传指针
func (c *Circle) changeRadius(radius float64)  {
   c.radius = radius
}

// 以下操作将不生效
//func (c Circle) changeRadius(radius float64)  {
//   c.radius = radius
//}
// 引用类型要想改变值需要传指针
func change(c *Circle, radius float64)  {
   c.radius = radius
}

// 这种是把【Circle类】作 为参数传递,并返回Circle类对象
func getArea2(c Circle) Circle {
	var temp Circle
	temp.radius = c.radius * 12
	return temp
 }
 
 // 这种是返回Circle类对象
 func getArea3() Circle {
	var temp Circle
	temp.radius = 0.999
	return temp
 }

3、闭包

go 复制代码
package main

import "fmt"

func getSequence() func() int {
   i := 0
   return func() int {
      i += 1
      return i
   }
}

func main() {
   /* nextNumber 为一个函数,函数 i 为 0 */
   nextNumber := getSequence()

   /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
   fmt.Println(nextNumber()) //这个执行结果是1
   fmt.Println(nextNumber()) //这个执行结果是2
   fmt.Println(nextNumber()) //这个执行结果是3

   /* 创建新的函数 nextNumber1,并查看结果 */
   nextNumber1 := getSequence() //当getSequence()被重新赋值之后,nextNumber的值应该销毁丢失的,但并没有
   fmt.Println(nextNumber1()) //这儿因为是新赋值的,所以是1
   fmt.Println(nextNumber()) //这一行代码是补充上例子的。这儿可不是新赋的值,重点说明这一个,这儿执行居然是4,这个值并没有被销毁,原因就是闭包导致的,尽管外面的函数销毁了,但是内部函数仍然存在,还可以继续走。这个就是闭包
   fmt.Println(nextNumber1()) //新赋值的,继续执行是2
}

4、指针

指针变量只能指向一个地址。

在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

go 复制代码
package main

import "fmt"

func main() {
   var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &a  ) // a 变量的地址是: 20818a220

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\n", ip ) // ip 变量储存的指针地址: 20818a220

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip ) // *ip 变量的值: 20
}

多级指针本质上就是一个指针链。

go 复制代码
package main

import (
   "fmt"  
)

func main()  { 
	var a int = 5
    // 指针
    var p1 *int = &a
    // 二级指针
    var p2 **int = &p1
    // 三级指针
    var p3 ***int = &p2

    fmt.Printf("p1的值:%d    p1的目标值:%d\n", p1, *p1) // p1的值:824633761992    p1的目标值:5
    fmt.Printf("p2的值:%d    p2的目标值:%d    p2的链尾目标值:%d\n", p2, *p2, **p2) // p2的值:824634196008    p2的目标值:824633761992    p2的链尾目标值:5
    fmt.Printf("p3的值:%d    p3的目标值:%d    下一个目标值:%d    p3的链尾目标值:%d\n", p3, *p3, **p3, ***p3) // p3的值:824634196016    p3的目标值:824634196008    下一个目标值:824633761992    p3的链尾目标值:5
   
}

向函数传递指针:

go 复制代码
package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int= 200

   fmt.Printf("交换前 a 的值 : %d\n", a )
   fmt.Printf("交换前 b 的值 : %d\n", b )

   /* 调用函数用于交换值
   * &a 指向 a 变量的地址
   * &b 指向 b 变量的地址
   */
   swap(&a, &b);

   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}

func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保存 x 地址的值 */
   *x = *y      /* 将 y 赋值给 x */
   *y = temp    /* 将 temp 赋值给 y */
   // *x, *y = *y, *x 可以优化为这个
}

5、map

go 复制代码
package main

import "fmt"

/*
使用 make 函数  其中 KeyType 是键的类型,ValueType 是值的类型,initialCapacity 是可选的参数,用于指定 Map 的初始容量。
map_variable := make(map[KeyType]ValueType, initialCapacity)
*/

func main() {

	// 创建一个空的 Map
	m := make(map[string]int)

	// 创建一个初始容量为 10 的 Map
	m := make(map[string]int, 10)

	// 使用字面量创建 Map
	m := map[string]int{
		"apple": 1,
		"banana": 2,
		"orange": 3,
	}

	// 获取键值对
	v1 := m["apple"]
	v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值

	// 修改键值对
	m["apple"] = 5

	// 获取 Map 的长度
	len := len(m)

	// 遍历 Map
	for k, v := range m {
		fmt.Printf("key=%s, value=%d\n", k, v)
	}

	// 删除键值对
	delete(m, "banana")



}

6、接口

go 复制代码
package main

import "fmt"

type Shape interface {
    area() float64
}

type Rectangle struct {
    width  float64
    height float64
}

func (r Rectangle) area() float64 {
    return r.width * r.height
}

type Circle struct {
    radius float64
}

func (c Circle) area() float64 {
    return 3.14 * c.radius * c.radius
}

func main() {
    var s Shape

    s = Rectangle{width: 10, height: 5}
    fmt.Printf("矩形面积: %f\n", s.area())

    s = Circle{radius: 3}
    fmt.Printf("圆形面积: %f\n", s.area())
}

7、异常

error 类型是一个接口类型,这是它的定义:

go 复制代码
type error interface {
    Error() string
}

我们可以在编码中通过实现 error 接口类型来生成错误信息。

函数通常在最后的返回值中返回错误信息。使用 errors.New 可返回一个错误信息:

go 复制代码
func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // 实现
}

示例:

go 复制代码
package main

import (
    "fmt"
)

// 自定义错误信息结构
type DIV_ERR struct {   
    etype int  // 错误类型   
    v1 int     // 记录下出错时的除数、被除数   
    v2 int
}
// 实现接口方法 error.Error()
func (div_err DIV_ERR) Error() string {   
    if 0==div_err.etype {      
        return "除零错误"   
    }else{   
        return "其他未知错误"  
    }
}
// 除法
func div(a int, b int) (int,*DIV_ERR) {  
    if b == 0 {     
        // 返回错误信息    
        return 0,&DIV_ERR{0,a,b}  
    } else {   
        // 返回正确的商  
        return a / b, nil   
    }
}
func main() { 
    // 正确调用  
    v,r :=div(100,2)  
    if nil!=r{   
        fmt.Println("(1)fail:",r)  
    }else{   
        fmt.Println("(1)succeed:",v) 
    }   
    // 错误调用
    v,r =div(100,0) 
    if nil!=r{   
        fmt.Println("(2)fail:",r)  
    }else{  
        fmt.Println("(2)succeed:",v) 
    }
}

三、包管理

1、go mod语法

bash 复制代码
# 新建项目
mkdir myapp && cd myapp
# 初始化项目,生成go.mod
go mod init myapp

# 指定国内包源地址
go env -w GOPROXY=https://goproxy.cn
# 下载echo包
go get github.com/labstack/echo/v4

#  更新依赖
go get -u xxx

# 删除项目中没有用到的依赖包
go mod tidy

# 查看当前项目依赖包
go list

2、项目下载所有依赖

bash 复制代码
## 第一步
go mod download 
## 第二步
go mod tidy
## 第三步
go list -m -json all
## 第四步
go mod vendor

## 执行完以上操作后,如果项目引入包爆红,或者项目可以正常运行,但引入的包报红,则执行以下方法。
## 第一步
go mod tidy
## 第二步
go mod vendor

要是还是不行(一般来说到第2步就可以了): 打开 GoLand 点击左上角: File-->Setting-->Go-->Go Modules-->Enable Go modules integration, 一般来说这样就可以了

相关推荐
Null箘1 分钟前
从零创建一个 Django 项目
后端·python·django
云空5 分钟前
《解锁 Python 数据挖掘的奥秘》
开发语言·python·数据挖掘
秋意钟10 分钟前
Spring新版本
java·后端·spring
青莳吖15 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall22 分钟前
期末考学C
java·开发语言
重生之绝世牛码24 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行30 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
Algorithm157640 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
shinelord明1 小时前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
A小白59081 小时前
Docker部署实践:构建可扩展的AI图像/视频分析平台 (脱敏版)
后端