Go语言快速入门教程(JAVA转go)——2 环境搭建与入门

发布于:2025-09-13 ⋅ 阅读:(16) ⋅ 点赞:(0)

安装go

Go官网下载地址:https://golang.org/dl/

中国区官方镜像站(推荐):https://golang.google.cn/dl/

windows安装

在这里插入图片描述

下载好后选择安装路径即可,安装完成后,win+r 输入cmd调出命令行窗口,输入

go version
# 回车后看到版本信息,就算安装成功了
go version go1.24.4 windows/amd64
Linux安装

如果要在linux系统下开发,就需要配置linux的开发环境。如果只需要在linux上运行打包好的程序的话,是不需要安装go环境的。因为,编译后的go,是可以跨平台运行的。

在版本选择页面选择并下载好go1.24.4.linux-amd64.tar.gz文件:

wget https://dl.google.com/go/go1.24.4.linux-amd64.tar.gz

文件解压到/usr/local目录下:

tar -zxvf go1.24.4.linux-amd64.tar.gz -C /usr/local  # 解压

需要加上sudo以root用户的身份再运行。执行完就可以在/usr/local/下看到go目录了。

配置环境变量: Linux下有两个文件可以配置环境变量,其中/etc/profile是对所有用户生效的;$HOME/.profile是对当前用户生效的,根据自己的情况自行选择一个文件打开,添加如下两行代码,保存退出。

export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin

修改/etc/profile后要重启生效,修改$HOME/.profile后使用source命令加载HOME/.profile文件即可生效。 检查:

~ go version
go version go1.23.1 linux/amd64
Mac下安装

mac下安装go,与windows基本相同,不再赘述了。

安装过程执行完毕后,可以打开终端窗口,输入go version命令,查看安装的Go版本。

环境变量

GOROOT和GOPATH都是环境变量,其中GOROOT是我们安装go开发包的路径

从Go 1.8版本开始,Go开发包在安装完成后,会为GOPATH设置一个默认目录,并且在Go1.14及之后的版本中启用了Go Module模式之后,不一定非要将代码写到GOPATH目录下,所以也就不需要我们再自己配置GOPATH了,使用默认的即可。

# 查看gopath
go env

在这里插入图片描述

代理

默认配置是:

GOPROXY=https://proxy.golang.org,direct

国内是访问不到的,我们要修改代理配置->https://goproxy.io

可以执行下面的命令修改GOPROXY:

go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOPROXY=https://mirrors.cloud.tencent.com/go/,direct

开发工具

vscode

下载地址:https://code.visualstudio.com/Download

安装go插件

插件商店搜索Rich Go language support for Visual Studio Code

Windows平台按下Ctrl+Shift+P,Mac平台按Command+Shift+P,这个时候VS Code界面会弹出一个输入框,输入以下指令

Go:Install/Update Tools

勾选全部工具,确定即可

在这里插入图片描述

编译运行

如果之前没有go项目文件夹,就新建文件夹==>vscode打开

将终端调到cmd终端,不使用powerShell终端,为什么不使用powerShell终端,是因为运行时的麻烦问题,例如,如果我们使用powerShell终端,运行 exe文件时要这么写:.\gohello.exe

在这里插入图片描述

通过go mod init 项目名命令对项目进行初始化,该命令会在项目根目录下生成go.mod文件。例如,我们使用gohello作为我们第一个Go项目的名称,执行如下命令。

go mod init gohello

创建一个main.go文件:

如果此时VS Code右下角弹出提示让你安装插件,务必点 install all 进行安装

  • 在 Go 语言中,只有首字母为大写的标识符才是导出的(Exported),才能对包外的代码可见;
  • 如果首字母是小写的,那么就说明这个标识符仅限于在声明它的包内可见。
  • 另外,在 Go 语言中,main 包是不可以像标准库 fmt 包那样被导入(Import)的,如果导入 main 包,在代码编译阶段你会收到一个 Go 编译器错误:import “xx/main” is a program, not an importable package。
package main    // 声明 main 包,表明当前是一个可执行程序,Go 语言中使用包来组织代码。一般一个文件夹即一个包

import "fmt"  // 导入内置 fmt 包,类似java中的system包

func main(){  // main函数,是程序执行的入口
	fmt.Println("Go Hello !")    // 在终端打印 Go Hello ! (所见即所得)
}

运行项目

go run main.go
gobuild
go build main.go

在这里插入图片描述

命令行输入以下命令,同样输出Go Hello !

main.exe

默认我们go build的可执行文件都是当前操作系统可执行的文件,Go语言支持跨平台编译——在当前平台(例如Windows)下编译其他平台(例如Linux)的可执行文件

Windows编译Linux可执行文件

在Windows下编译一个Linux下可执行文件,那需要怎么做呢?只需要在编译时指定目标操作系统的平台和处理器架构即可。

如果你的Windows使用的是cmd,那么按如下方式指定环境变量。

SET CGO_ENABLED=0  // 禁用CGO
SET GOOS=linux  // 目标平台是linux
SET GOARCH=amd64  // 目标处理器架构是amd64

如果你的Windows使用的是PowerShell终端,那么设置环境变量的语法为

$ENV:CGO_ENABLED=0
$ENV:GOOS="linux"
$ENV:GOARCH="amd64"

在你的Windows终端下执行完上述命令后,再执行下面的命令,得到的就是能够在Linux平台运行的可执行文件了。

go build

依赖管理

添加依赖

当你运行go get来添加新的依赖或者更新现有依赖时,这些依赖会被自动添加到go.mod文件中。例如

go get github.com/tools/godep

在这里插入图片描述

更新依赖

运行以下命令来更新所有依赖到最新的兼容版本:

go get ./...
管理依赖

go.mod文件会记录项目的依赖和对应的版本。你可以手动编辑go.mod文件来指定依赖版本,但不推荐这样做,除非你需要引入特定的bug修复版本或者必须使用某个未发布的版本。

下载依赖

比如当你从代码仓库下载某一个新项目时,运行以下命令来下载项目所有依赖到本地缓存:

go mod download

查看当前项目的依赖

go list -m all
处理依赖冲突

Go Modules会自动处理依赖版本冲突。如果发生冲突,它会选择一个最新的兼容版本。如果需要,你可以手动解决冲突。

Web服务实战

Go 应用的前 4 个领域中,有两个都是 Web 服务相关的。一个是排在第一位的 API/RPC 服务,另一个是排在第四位的 Web 服务(返回 html 页面)。考虑到后续把 Go 应用于 Web 服务领域的机会比较大,所以,这里我们就选择一个 Web 服务项目作为实战小项目。

HTTP服务

先来给你演示一下在 Go 中创建一个基于 HTTP 协议的 Web 服务是多么的简单

首先按下面步骤建立一个 simple-http-server Go Module

go mod init simple-http-server

创建一个 main.go 源文件

package main

import "net/http"

func main() {
    //注册一个处理函数,当用户访问网站根路径 / 时触发
    //(响应对象w:用于向客户端发送响应数据,请求对象r:包含客户端发来的所有请求信息(如 URL、Header、Body 等))
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
        w.Write([]byte("hello, world"))
    })
    
    //启动 HTTP 服务器,监听本机的 8080 端口。
    http.ListenAndServe(":8080", nil)  //使用默认的多路复用器
}

当你运行这个程序后,在浏览器地址栏输入:http://localhost:8080/

你将会看到页面上显示:hello, world

图书管理 API 服务

首先,我们先来明确一下我们的业务逻辑。

在这个实战小项目中,我们模拟的是真实世界的一个书店的图书管理后端服务。这个服务为平台前端以及其他客户端,提供针对图书的 CRUD(创建、检索、更新与删除)的基于 HTTP 协议的 API。API 采用典型的 RESTful 风格设计,这个服务提供的 API 集合如下:

在这里插入图片描述

布局设计

我们按照下面步骤创建一个名为 bookstore 的 Go 项目并创建对应的 Go Module:

go mod init  bookstore 

通过上面的业务逻辑说明,可以把这个服务大体拆分为两大部分

  • 一部分是 HTTP 服务器,用来对外提供 API 服务;
  • 另一部分是图书数据的存储模块,所有的图书数据均存储在这里。

我们参考 Go 项目布局标准中的项目布局,把这个项目的结构布局设计成这样:

├── cmd/
│   └── bookstore/         // 放置bookstore main包源码
│       └── main.go
├── go.mod                 // module bookstore的go.mod
├── go.sum
├── internal/              // 存放项目内部包的目录
│   └── store/
│       └── memstore.go     
├── server/                // HTTP服务器模块
│   ├── middleware/
│   │   └── middleware.go
│   └── server.go          
└── store/                 // 图书数据存储模块
    ├── factory/
    │   └── factory.go
    └── store.go

在这里插入图片描述

main

main 包不仅包含了整个程序的入口,它还是整个程序中主要模块初始化与组装的场所。

package main
import (
    _ "bookstore/internal/store" //只运行这个包的 init() 函数,不直接使用它的导出内容
    "bookstore/server"
    "bookstore/store/factory"
    "context"
    "log"
    "os"     //处理系统信号,比如 Ctrl+C
    "os/signal"
    "syscall"
    "time"   //用于设置超时时间
)

func main() {
    s, err := factory.New("mem")     // 创建图书数据存储模块实例
    if err != nil {
        panic(err)   //如果失败,则 panic 终止程序
    }

    srv := server.NewBookStoreServer(":8080", s) // 创建http服务实例

    errChan, err := srv.ListenAndServe() // 运行http服务
    if err != nil {
        log.Println("web server start failed:", err)
        return
    }
    log.Println("web server start ok")
	
    //创建一个通道 c,用于接收操作系统发送的中断信号(例如 Ctrl+C 或 kill 命令)
    c := make(chan os.Signal, 1)
    signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)  //监听信号
	
    //使用 select 同时监听errChan以及c两个事件,实现优雅退出
    select { 
        case err = <-errChan:
        	log.Println("web server run failed:", err)
        	return
        case <-c:
        	log.Println("bookstore program is exiting...")
       		ctx, cf := context.WithTimeout(context.Background(), time.Second)
       		defer cf()
        	err = srv.Shutdown(ctx) // 优雅关闭http服务实例
    }

    if err != nil {
        log.Println("bookstore program exit error:", err)
        return
    }
    log.Println("bookstore program exit ok")
}
store

存储整个 bookstore 的图书数据。图书数据存储有很多种实现方式,最简单的方式莫过于在内存中创建一个 map,以图书 id 作为 key,来保存图书信息,我们在这一讲中也会采用这种方式。但如果我们要考虑上生产环境,数据要进行持久化,那么最实际的方式就是通过 Nosql 数据库甚至是关系型数据库,实现对图书数据的存储与管理。

package store
type Book struct {
     Id      string   `json:"id"`      // 图书ISBN ID
     Name    string   `json:"name"`    // 图书名称
     Authors []string `json:"authors"` // 图书作者
     Press   string   `json:"press"`   // 出版社
 }
 
 type Store interface {
     Create(*Book) error        // 创建一个新图书条目
     Update(*Book) error        // 更新某图书条目
     Get(string) (Book, error)  // 获取某图书信息
     GetAll() ([]Book, error)   // 获取所有图书信息
     Delete(string) error       // 删除某图书条目
 }

对于想要进行图书数据操作的一方来说,他只需要得到一个满足 Store 接口的实例,就可以实现对图书数据的存储操作了,不用再关心图书数据究竟采用了何种存储方式。这就实现了图书存储操作与底层图书数据存储方式的解耦。

store/factory 实现满足 Store 接口实例的创建。

package factory
// store/factory/factory.go
var (
	providersMu sync.RWMutex
	providers   = make(map[string]store.Store)
)

func Register(name string, p store.Store) {
	providersMu.Lock()
   defer providersMu.Unlock()
	if p == nil {
		panic("store: Register provider is nil")
	}

	if _, dup := providers[name]; dup {
		panic("store: Register called twice for provider " + name)
	}
	providers[name] = p
}

func New(providerName string) (store.Store, error) {
	providersMu.RLock()
	p, ok := providers[providerName]
	providersMu.RUnlock()
	if !ok {
		return nil, fmt.Errorf("store: unknown provider %s", providerName)
	}

	return p, nil
}