系统仍旧是廉颇老矣的windows7,所以很多软件的新版本都没法运行,就像go已经出到了1.26版本,但win7上仅支持1.20.14,再往上就不受支持了,所以下方的代表仅在上述版本中验证通过。学习go语言的第一感受是,go语言取消了c++里两者皆可的表达,而直接帮用户选择了使用频率更高的其中一种表达方式。
安装版的直接无脑下一步就好,暂时就不挑战手动配置环境了,怕耽误自己本就如风中残烛般的学习热情。安装完后可以直接在cmd或者powershell中运行go指令,就很方便,这里更推荐powershell,cmd部分指令无法正确运行。
创建工作文件夹
比如博主准备在d盘根目录下建立一个工作文件夹:
mkdir goPress
cd goPress
//这会创建一个 go.mod 文件,用来管理你的项目依赖
//注意这里的init后面的命名会影响到导入包的路径名称
go mod init goPress
//创建一个main.go文件
New-Item -ItemType File -Path main.go
//上述的指令可以简写为
ni main.go -type file接下来可以随便找个文本编辑器来编辑这个go文件了,这里博主使用的是sublime。
你好,世界
国际惯例运行一个Hello world!,注意go语言不需要在行末添加分号,将以下语句保存至main.go;
package main
import "fmt"
func main() {
fmt.Println("你好,世界!")
}然后在powershell里运行如下指令,我们就能看见经典的入门案例的输出了;
//下面的"main.go"可以 简写为 "."
PS D:\goPress> go run main.go常量与变量
//定义变量
var identifier type = value
var identifier1, identifier2 type = value1, value2
//定义常量
const identifier [type] = value运算符
运算符和c++很像,有c++基础的应该会觉得很亲切,其原因可能是因为其创始人都深受C语言影响:
- Ken Thompson:B语言作者、C语言共同作者、Unix之父
- Rob Pike:贝尔实验室Unix团队核心成员
- Robert Griesemer:也有深厚的C/系统编程背景
与c++主要差异如下:
无三元运算符
无指针算术
无隐式类型转换
增加channel运算符 <- 和位清空 &^
++/-- 只能后缀且为语句
......
循环与判断
循环语句:
//常规用法
for init; condition; post { }
//类似while,顺便一提,go里没有while
for condition { }
//无限循环
for { }数组的遍历
func main(){
chars:=[]string{"a","b","c","d","e"}
for key,value:=range chars{
fmt.Println(key , value)
}
for key:=range chars{
fmt.Println(key)
}
for _,value:=range chars{
fmt.Println(value)
}
}判断语法:
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}函数
func function_name( [parameter list] ) [return_types] {
函数体
}func:函数由 func 开始声明;
function_name:函数名称,参数列表和返回值类型构成了函数签名;
parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数;
return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的;
函数体:函数定义的代码集合。
需要注意的是,Go 允许函数返回多个值。
数组与切片
在 Go 语言中,数组和切片的核心定义区别在于:长度是否固定。
func main() {
var arr1 [5] int
var arr2 = [3]string{"a","b","c"}
var arr4 = [3][3]int{
{1,2,3},
{4,5,6},
{7,8,9},
}
fmt.Println(arr1)
fmt.Println(arr2)
fmt.Println(arr3)
fmt.Println(arr4)
}数组是定长的值类型,切片是变长的引用类型。在实际开发中,切片远比数组常用。
var s []int // 不指定长度,长度可变
s = append(s, 1) // 可动态增加元素切片的扩容规则
因为 go 的切片扩容策略:初始容量:5(刚好装下 1,2,3,4,5),追加第6个元素时:容量不足,触发扩容。
go 扩容规则:当容量 < 1024 时,通常翻倍(5 → 10),当容量 ≥ 1024 时,增长约 25%。
指针
go有选择性地限制了指针的某些危险特性(别说危险特性了,安全特性博主也没学明白呢)。
func main() {
var a,b int = 1,2
var p1 *int = &a
var p2 *int = &b
fmt.Println(a,b)
swap(p1,p2)
fmt.Println(a,b)
}
func swap(a,b *int){
*a,*b=*b,*a
}结构体
type Books struct {
title string
author string
subject string
bookid int
}
func main(){
var book1 = Books{
title: "a",
author: "b",
subject: "c",
bookid: 0,
}
var book2 Books
book2.title = "d"
book2.author = "e"
book2.subject = "f"
book2.bookid = 1
fmt.Println(book1, book2)
}range范围
Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
newMap[key] = value
}Map(集合)
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 ""。Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。
func main() {
var site = make(map[string]string,10)
site["google"]="谷歌"
site["baidu"]="百度"
site["abddb"]="小鸟数据"
site["wiki"]="维基"
for key,value := range site {
fmt.Println(key,"站点名称是",value)
}
}递归
学习到递归的内容,说明这门语言要开始折磨你了:
package main
import "fmt"
var arr = [100]int{0,1}
func digui(n int) int {
if n == 1 {
return 1
}
if arr[n]!=0 {
return arr[n]
}else{
arr[n] = n * digui(n - 1)
return arr[n]
}
}
func main() {
digui(10)
for i:=0;i<10;i++{
fmt.Println(arr[i])
}
}闭包
闭包(Closure)这一概念,在一些语言中又被称为 Lambda 表达式,与匿名函数一起使用,闭包 = 函数 + 环境引用。看下面一个例子:
package main
import "fmt"
func Exp(n int) func() int {
e := 1
return func() int {
temp := e
e *= n
return temp
}
}
func main() {
grow := Exp(2)
for i := 1; i < 10; i++ {
fmt.Println("2^", i, "=", grow())
}
}利用闭包实现斐波那契数列的实例:
package main
import "fmt"
func Fib(n int) func() int {
i := 0
a, b, c := 1, 1, 2
return func() int{
if(i>n){
return -1
}else if i<2{
f := i
i++
return f
}else{
i++
a,b = b,c
c = a+b
return a
}
}
}
func main(){
a:=Fib(10)
for i:= a();i!=-1;i=a(){
fmt.Println(i)
}
}数据类型转换
| 源类型 | 目标类型 | 转换方式 | 注意事项 |
|---|---|---|---|
int |
float64 |
float64(i) |
可能产生小数部分 |
float64 |
int |
int(f) |
截断小数,不是四舍五入 |
int |
string |
strconv.Itoa(i) |
不要用 string(i)(会转为Unicode字符) |
string |
int |
strconv.Atoi(s) |
需要处理 error |
string |
[]byte |
[]byte(s) |
复制数据 |
[]byte |
string |
string(b) |
复制数据 |
interface{} |
具体类型 |
value.(Type) |
使用 ok 模式避免 panic |
接口
接口(interface)是 Go 语言中的一种类型,用于定义行为的集合,它通过描述类型必须实现的方法,规定了类型的行为契约。Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。Go 的接口设计简单却功能强大,是实现多态和解耦的重要工具。接口可以让我们将不同的类型绑定到一组公共的方法上,从而实现多态和灵活的设计。
接口常见用途
- 多态:不同类型实现同一接口,实现多态行为。
- 解耦:通过接口定义依赖关系,降低模块之间的耦合。
- 泛化:使用空接口 interface{} 表示任意类型。
接口实例
package main
import "fmt"
import "math"
type Shape interface {
area() float64
}
type Circle struct {
radius float64
}
type Square struct {
lenth float64
width float64
}
func (c Circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (s Square) area() float64 {
return s.lenth * s.width
}
func main() {
var s = Square {
lenth : 6.0,
width : 5.1,
}
var c = Circle {
radius : 10,
}
fmt.Println(s.area())
fmt.Println(c.area())
}错误处理
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。Go 语言的错误处理采用显式返回错误的方式,而非传统的异常处理机制。这种设计使代码逻辑更清晰,便于开发者在编译时或运行时明确处理错误。Go 的错误处理主要围绕以下机制展开:
- error 接口:标准的错误表示。
- 显式返回值:通过函数的返回值返回错误。
- 自定义错误:可以通过标准库或自定义的方式创建错误。
- panic 和 recover:处理不可恢复的严重错误。
一个错误演示
package main
import "fmt"
import "errors"
func power(x int) (int, error) {
if x > 10 {
return 0 , errors.New("too big")
} else {
return x * x , nil
}
}
func main() {
var res int
var err error
res,err = power(11)
if err != nil {
fmt.Println("计算出错:", err)
return
}
fmt.Println(res)
}

