极简Go语言教程

公众号:Hoeller

教程中涉及到Go的知识点有:安装、变量、常量、特殊常量iota、切片、结构体、函数、方法、接口、指针。

安装

安装地址:golang.google.cn/dl/,按操作系统选择安装包

配置环境变量

  1. Windows将c:\Go\bin配置到Path环境变量中
  2. Mac不需要额外配置
  3. Linux将解压出来的目录中的bin目录配置到Path环境变量中

验证版本

在命令行执行go version输出版本则表示安装成功

java 复制代码
dadudu@dadududeMBP ~ % go version
go version go1.21.3 darwin/arm64

Hello World

在任意地方新建文件hello.go,内容为

go 复制代码
package main

import "fmt"

func main() {
    fmt.Println("Hello, World")
}

然后运行go run hello.go即可得到输出结果:"Hello, World"。

变量

go里面用var来定义变量,名字在前,类型在后,并且可以一次定义多个变量

go 复制代码
package main
import "fmt"
func main() {
	var a string = "dadudu"
	var b, c int = 1, 2
	fmt.Println(a,b,c)
}

类型推导

也可以直接不写类型,go会根据值自动推导出变量的类型

go 复制代码
var a = "dadudu"
var b, c = 1, 2

:=定义变量

因为有了类型推导,所以var关键字也可以不写,使用:=来定义变量并赋值

go 复制代码
package main

import "fmt"

func main() {
	a := "dadudu"
	b, c := 1, 2

	fmt.Println(a, b, c)
}

修改变量

变量是可以修改的,直接用=给变量赋不同的值就可以了

go 复制代码
a = "xiaodudu"

注意:=是用来定义变量的,不能用来修改变量。

常量

常量就是定义并初始化后就不能修改了,语法上跟变量一样,只是关键字用const

go 复制代码
package main

import "fmt"

func main() {
	const a = "dadudu"
	//a = "xiaodudu" 此处编译报错

	fmt.Println(a)
}

也可以一次性定义多个常量:

go 复制代码
func main() {
	const a, b, c = "dadudu", 1, 2
	fmt.Println(a, b, c)
}

但是const关键字不能省略,不然就成了变量,但是如果确实有多个常量需要定义,或者定义枚举,还可以这样写

go 复制代码
func main() {
	const (
		creating = 0
		created  = 1
		unpaid   = 2
		paid     = 3
	)
	fmt.Println(creating, created, unpaid, paid)
}

输出结果为:0 1 2 3

特殊常量iota

以上代码可以简化为:

go 复制代码
func main() {
	const (
		creating = iota
		created
		unpaid
		paid
	)
	fmt.Println(creating, created, unpaid, paid)
}

输出结果同样为:0 1 2 3,赋值了iota的常量的值是0,后续的常量会自动加1,如果在四个常量中间新增了常量,那么五个常量的值会自动改变:

go 复制代码
func main() {
	const (
		creating = iota
		created
		createFailed // 新增
		unpaid
		paid
	)
	fmt.Println(creating, created, createFailed, unpaid, paid)
}

输出结果为:0 1 2 3 4,这样就能省掉程序员手动调整常量值的麻烦(想想Java中要怎么做....)

切片

go里有数值和切片两种类型,分别是这么定义的:

go 复制代码
func main() {
	a := [5]int{1, 2, 3, 4, 5} // 数组
	b := []int{1, 2, 3, 4, 5}  // 切片
	fmt.Println(a, b)
}

数组长度不可变,切片长度可变,所以切片也叫做动态数组。

比如,可以给切片添加元素:

go 复制代码
func main() {
	a := [5]int{1, 2, 3, 4, 5} // 数组
	b := []int{1, 2, 3, 4, 5}  // 切片

	b = append(b, 6)
	
	fmt.Println(a, b)
}

输出结果为:

go 复制代码
[1 2 3 4 5] 
[1 2 3 4 5 6]

切片没有直接提供remove方法,可以通过append方法间接删除,以下代码会删除掉切片中下标为1的元素(2):

go 复制代码
func main() {
	a := [5]int{1, 2, 3, 4, 5} // 数组
	b := []int{1, 2, 3, 4, 5}  // 切片

	b = append(b[:1], b[2:]...)

	fmt.Println(a, b)
}

输出结果为:

go 复制代码
[1 2 3 4 5]
[1 3 4 5]

另外,数组和切面都可以截取范围来访问元素:

go 复制代码
func main() {
	a := [5]int{1, 2, 3, 4, 5} // 数组
	b := []int{1, 2, 3, 4, 5}  // 切片
	
	fmt.Println(a[1:4], b[2:5])
}

输出结果为:

go 复制代码
[2 3 4] 
[3 4 5]

结构体

如果你想要有一个"对象",那么就可以定义一个结构体并构造出"对象":

go 复制代码
type User struct {
	id   int
	name string
	age  int
}

func main() {
    // 创建User对象
	user := User{1, "dadudu", 18}

    // 输出对象的name属性
	fmt.Println(user.name)
}

函数与方法

Java只有方法,要么是静态方法(归属于类),要么是普通方法(归属于对象),go中分为函数与方法。

go 复制代码
type User struct {
	id   int
	name string
	age  int
}

func getNameAndAge(user User) (string, int) {
	return user.name, user.age
}

func main() {
	// 创建User对象
	user := User{1, "dadudu", 18}

	name, age := getNameAndAge(user)

	fmt.Println(name, age)
}

以上getNameAndAge就是一个函数,接收一个User类型对象,返回一个string和一个int,有点类似于Java的静态方法,不需要生成对象才能调用,直接调就可以了,但是强大的地方在于,一个函数可以有多个返回值(这个是真好用...)。

以下代码中的getNameAndId就是一个方法,并且该方法跟User结构体绑定在一起了,而函数是没有和某个结构体绑定的,调用方法就需要对象才能调用

go 复制代码
// 函数
func getNameAndAge(user User) (string, int) {
	return user.name, user.age
}

// 方法
func (user User) getNameAndId() (string, int) {
	return user.name, user.id
}

func main() {
	// 创建User对象
	user := User{1, "dadudu", 18}

	name, age := getNameAndAge(user)
	name, id := user.getNameAndId()

	fmt.Println(id, name, age)
}

接口

Java中,需要在代码中先实现接口,然后必须实现接口中的方法,而在go中,一个结构体只要实现了某个接口的所有方法,那么这个结构体就是这个接口的"实现类"。

go 复制代码
type Person interface {
	getName() string
	getAge() int
}

type User struct {
	id   int
	name string
	age  int
}

func (user User) getName() string {
	return user.name
}

func (user User) getAge() int {
	return user.age
}

func main() {
	var person Person = User{1, "dadudu", 18} // 赋值语句
	fmt.Println(person)
}

以上代码中,由于给User结构体绑定了getName()getAge()方法,所以User实现了Person接口中的两个方法,也就相当于User实现了Person接口,所以可以把User对象直接赋值给Person类型的变量。但凡注释掉其中一个方法,赋值语句都将报错。

指针

变量表示值,而指针表示值所在的内存地址,其实就是跟Java中的值传递和引用传递类似,比如以下代码:

go 复制代码
func test(a int) {
	a = 2
}

func main() {
	a := 1
	test(a) // 修改了a的值
	fmt.Println(a)
}

最终输出的的a为1,虽然test函数中修改了a的值,但由于是指传递,传递给test函数的是一个副本,所以原本的a并没有发生改变。

而一旦把代码改成:

go 复制代码
func test(a *int) {
	*a = 2  // 将指针位置的值改为2
}

func main() {
	a := 1
	test(&a) // 传入a的指针
	fmt.Println(a)
}

输出的a就是2了,因为传给test函数是a的指针,并且test函数中会把指针位置的值改为2。

极简Go教程就到这啦,大家如果觉得这种极简风格还可以,还想看其他语言的,记得点赞、收藏、分享告诉我哦~

欢迎大家关注我的公众号:Hoeller,第一时间接收我的原创技术文章,你将收获更多干货知识。

相关推荐
南山十一少2 小时前
Spring Security+JWT+Redis实现项目级前后端分离认证授权
java·spring·bootstrap
闲猫4 小时前
go orm GORM
开发语言·后端·golang
427724004 小时前
IDEA使用git不提示账号密码登录,而是输入token问题解决
java·git·intellij-idea
丁卯4044 小时前
Go语言中使用viper绑定结构体和yaml文件信息时,标签的使用
服务器·后端·golang
chengooooooo4 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
李长渊哦4 小时前
常用的 JVM 参数:配置与优化指南
java·jvm
计算机小白一个4 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
南宫生7 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
计算机毕设定制辅导-无忧学长7 小时前
Maven 基础环境搭建与配置(一)
java·maven
bing_1588 小时前
简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
spring boot·后端·简单工厂模式