Go语言简介
2007年末由Robert Griesemer, Rob Pike(Bell实验室最早Unix开发者之一), Ken Thompson(C和Unix的发明人,图灵奖得主)在Google公司主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。
特点:
- 静态类型语言。
- 语言层面支持并发。
- 内置runtime,支持垃圾回收。
- 简单易学,语言简洁。
- 丰富的标准库。
- 内置强大的工具。
- 跨平台编译。
Go下载地址是:golang.google.cn/dl/
语法特征
- 包系统
- 变量与赋值
- 动态列表slice
- 词法作用域
- 一等公民函数
- 系统调用接口
未实现的功能:
- 隐式数值类型强制转换
- 构造函数和析构函数
- 运算符重载、默认参数、继承、异常、宏、线程局部存储
数据类型
语法特点:类型后置
基本数据类型:
# 整型
var i int8 = 1
# 浮点数
var f float32 = 1.1
#常量
const e = 2.1
#复数
var x complex128 = complex(1,2)
var y complex128 = complex(3,4)
#布尔
var a bool = true
#字符串
s := "hello, world"
复合类型
#数组
var q [4]int = [4]int{1,2,3,4}
#Slice
months := [...]string{1:"January", /*...*/, 12: "December"}
#map
ages := make(map[string]int)
#结构体
type Employee struct{
ID int
Name string
}
#json
object{
"year": 1980,
"event": "archery",
"medals": ["gold", "silver", "bronze"]
}
赋值
=是赋值,:=是声明变量并赋值
=的使用必须使用先var声明例如:
var a
a=100
//或
var b = 100
//或
var c int = 100
:=是声明并赋值,并且系统自动推断类型,不需要var关键字
d := 100
多变量赋值,例如b, a = a, b直接交换变量取值
循环
for循环
for i := 0; i < 5; i++ {
fmt.Println(i)
}
无限循环
for {
fmt.Println("Infinite loop")
}
键值循环
for range 结构是一种迭代结构,可以遍历数组、切片、字符串、map 及通道(channel),一般形式为:
for key, val := range coll {
...
}
//i.e.
for key, val := range []int{1,2,3}{
fmt.Println("key:%d, value:%d\n", key, value)
}
输出:
key:0, value:1
key:1, value:2
key:2, value:3
通过 for range 遍历的返回值有一定的规律:
- 数组、切片、字符串返回索引和值。
- map 返回键和值。
- 通道(channel)只返回通道内的值。
数组与Slice
Go语言的数组和C语言的数组在数据结构上是一样的,相同点都是开一个连续的空间存储数据;两种语言编写的静态数组和动态数组在内存分配方式上几乎相同
动态数组分配上,而C语言采用的实际开空间的模式,借用我们常用的malloc等函数,而Go语言的动态数组实际上是一段内存地址指向的模式,也就是动态列表slice。
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个 slice 类型一般写作 []T,其中T代表 slice 中元素的类型;slice 的语法和数组很像,只是没有固定长度而已。
一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。
多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠。
slice := []int{1, 2, 3}
slice = append(slice, 4)
一等公民函数
在编程语言设计中,给定编程语言中的一等公民(也就是类型,对象,实体或值)可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值来直接使用。Go语言中的函数就满足这一定义。
Go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一些简单的功能。所谓匿名函数,就是没有名称的函数。
hello := function(name string){
fmt.Println("hello %v", name)
}
hello("juejin")
函数被看作第一类值(first-class values):函数像其他值一样,拥有类型,可以被赋值给其他变量,传递给函数,从函数返回。对函数值(function value)的调用类似函数调用。
函数闭包
在Go中,闭包在底层是一个结构体对象,它包含了函数指针与自由变量。Go编译器的逃逸分析机制,会将闭包对象分配至堆中,这样自由变量就不会随着函数栈的销毁而消失,它能依附着闭包实体而一直存在。
垃圾回收
Go1.3 标记清除法
Go1.5 三色标记法
Go1.8 三色标记+混合写屏障
并发
Go语言作为新兴的语言,最近发展势头很是迅猛,其最大的特点就是原生支持并发。它使用的是“协程(goroutine)模型”,和传统基于 OS 线程和进程实现不同,Go语言的并发是基于用户态的并发,这种并发方式就变得非常轻量,能够轻松运行几万并发逻辑。Go 的并发属于 CSP 并发模型的一种实现,CSP 并发模型的核心概念是:“不要通过共享内存来通信,而应该通过通信来共享内存”。这在 Go 语言中的实现就是 Goroutine 和 Channel。
每一个并发的执行单元叫作一个 goroutine。一个 goroutine 可类比一个线程。
go func() {
fmt.Println("Running in a goroutine")
}()
Channels用于不同Goroutines之间的通信,确保数据的同步
ch := make(chan string) go func() {
ch <- "Hello from Goroutine"
}()
fmt.Println(<-ch) // 输出:Hello from Goroutine
错误处理
Go 提供了一种简洁而有效的错误处理机制,通过 error 类型来表示错误。Go 的错误处理遵循一种显式而简单的方式,函数通常返回一个错误值,如果没有错误,返回值为 nil。
if err != nil {
log.Fatal(err)
}
总结
Go 语言是一种功能强大且特色鲜明的编程语言,它融合了静态类型、高效的并发处理、自动垃圾回收等诸多优势,语法简洁又不失丰富性。从数据类型、赋值操作、循环结构到函数特性、垃圾回收机制、并发与错误处理等各个方面,都展现出独特的设计理念。无论是初学者还是有经验的开发者,都能在 Go 语言中找到适合的应用场景和开发乐趣,它为软件开发领域提供了一个高效、可靠的开发选择。