Hello, World!
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
数据类型
- 布尔型:bool
- 数字类型: int, int8~64, uint, uint8~64, float, float32, float64, complex64, complex128, byte, rune, uintptr
- 字符串类型:string
- 派生类型:
(a) 指针类型(Pointer)
(b) 数组类型
( c ) 结构化类型(struct)
(d) 函数类型
(e) 切片类型
(f) 接口类型(interface)
(g) Map 类型
(h) Channel 类型 - 类型转换
type_name(expression)
变量
局部变量、全局变量、形参的作用域与C语言类似
package main
var x, y int
var ( // 声明全局变量
a int
b bool
)
var c, d int = 1, 2
var e, f = 123, "hello"
// 这种不带声明格式的只能在函数体中体现
// g, h := 123, "hello"
func main() {
g, h := 123, "hello"
println(x, y, a, b, c, d, e, f, g, h)
常量
常量只可以是布尔型、数字型、字符串型
package main
import "fmt"
func main() {
const LENGHT int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" /// 多重赋值
area = LENGHT * WIDTH
fmt.Printf("面积为: %d", area)
println()
println(a, b, c)
}
iota特殊常量,自增长
package main
import "fmt"
func main() {
const (
a = iota // 0
b // 1
c // 2
d = "ha" // 独立值, iota += 1
e // “ha” iota += 1
f = 100 // iota += 1
g // 100 iota += 1
h = iota // 7
i // 8
}
fmt.Println(a, b, c, d, e, f, g, h, i)
}
运算符
和C语言运算符用法类似
-
算术运算符:+ - * / % ++ –
-
关系运算符:== != > < >= <=
-
逻辑运算符:&& || !
-
位运算符:& | ^ << >>
-
赋值运算符:= += -= *= /= %= <<= >>= &= ^= |=
-
其他运算符:取地址 &, 指针变量 *
-
运算符优先级:和C语言差不多
条件语句
if…else if…else
package main
import "fmt"
func main() {
var a int = 40
if (a < 20) {
// 小于20
if a < 10 {
// 小于10
}
} else if a < 30 {
// 小于30
} else {
// 大于等于30
}
}
switch…case
package main
import "fmt"
func main() {
var grade string = "B"
var marks int = 90
switch marks {
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70: grade = "C"
default: grade = "D"
}
switch {
case marks == 90 :
fmt.Printf("优秀!\n")
case grade == "B", grade == "C" :
fmt.Printf("良好!\n")
case grade == "D" :
fmt.Printf("及格!\n")
case grade == "F":
fmt.Printf("不及格!\n")
default:
fmt.Print("差!\n")
}
fmt.Printf("你的等级是 %s\n", grade)
}
循环语句
for循环有4种形式。for循环可以嵌套。控制语句break, continue, goto语法和C语言一样。
-
for init; condition; post {}
类似C语言的for -
for condition {}
类似C语言的while -
for {}
类似C语言的for(; ? -
for i, x := range array {}
for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
例子:
package main
import "fmt"
func main() {
var b int = 15
var a int
numbers := [6]int{1, 2, 3, 5}
for a := 0; a < 10; a++ {
fmt.Printf("a的值为: %d\n", a)
}
for a < b {
a++
fmt.Printf("a的值为: %d\n", a)
}
for i, x := range numbers {
fmt.Printf("第%d位x的值=%d\n", i, x)
}
}
函数
函数定义格式如下:
func function_name([parameter list]) [return_types] {
函数体
}
传值参数
func max(num1, num2 int) int {
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
传地址参数
func swap(x *int, y *int) {
var temp int
temp = *x
*x = *y
*y = temp
}
函数支持递归调用。函数可以返回多个值。
package main
import “fmt”
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Kobe", "Messi")
fmt.Println(a, b)
}
函数变量
package main
import (
“fmt”
"math"
)
func main() {
/* 声明函数变量 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
/* 使用函数 */
fmt.Println(getSquareRoot(9))
}
使用匿名函数做为闭包
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())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
// 创建新的函数 nextNumber1, 并查看结果
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
结构体和其方法
package main
import (
"fmt"
)
// 定义结构体
type Circle struct {
radius float64
}
// Circle的方法
func (c Circle) getArea() float64 {
return 3.14 * c.radius * c.radius
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("Area of Circle(c1) = ", c1.getArea())
}
数组
数组声明需要指定元素类型及元素个数,语法格式如下:
var variable_name[SIZE] variable_type
例子:
var a [10]float32
var b = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0} // 初始化数组中{}中的元素个数可以小于或等于[]中的数字
var c = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
var d [5][10][4]int
e := [3][4]int{
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}
}
向函数传递数组
func getAverage(arr []int, size int) float32 {
}
遍历数组
package main
import "fmt"
func main() {
var n [10]int
var i, j int
for i = 0; i < 10; i++ {
n[i] = i + 100
}
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j])
}
}
指针
package main
import "fmt"
func main() {
var a int = 20
var ip *int
ip = &a
fmt.Printf(“a变量的地址是:%x\n”, &a)
fmt.Printf(“ip变量存储的指针地址是:%x\n”, ip)
fmt.Printf(“ip变量指向地址存储的值是:%d\n”, *ip)
}
空指针判断:
if (ptr != nil) {}
if (ptr == nil) {}
指针数组:
var ptr [10]*int
执行指针的指针变量:
var ptr **int
结构体
结构体变量和结构体指针变量,访问结构体成员都是用点号 .
type Books struct {
title string
author string
subject string
book_id int
}
var book1 = Books{"Go语言", "Jack", "Go语言教程", 100}
// 也可以使用key : value格式初始化
book2 := Books{title : "Go语言", subject : "Go语言教程", author : "Jack", book_id : 100}
// 忽略的字段为0或空
book3 := Books{title : "Go语言", author : "Jack"}
切片(Slice)
切片是引用类型,是对数组的一个连续片段的引用。多个切片如果引用同一个数组,他们共享同一个数组的内存。
声明切片与声明数组的差别:声明切片时 [ ]中是空的;声明数组时[ ]中有数组长度或者…符号
var identifier []type
例子:
s := []int{1, 2, 3}
// 使用make()函数来创建切片
make([]T, length, capacity)
// 将数组或者切片arr中从下标startIndex到endIndex-1下的元素创建为一个新的切片
s := arr[startIndex : endIndex]
举例:
package main
import "fmt"
func main() {
// 创建数组
arrays := [...]int{0,1,2,3,4,5,6,7,8}
// 创建切片number1引用数组arrays
number1 := arrays[:]
// 创建切片number2引用数组arrays
number2 := number1[:]
// 扩容后,底层创建了新的数组,number1引用了新数组
number1 = append(number1, 9,10,11)
// 这里只改变了新数组内存的值,arrays数组值没变
number1[0] = 88
printSlice(number1)
printSlice(number2)
// 这里没有改变number2的引用,只是将number1引用的数组值拷贝到number2引用的数组arrays中,超长的部分截断。
copy(number2, number1)
printSlice(number2)
fmt.Println(array[0]) // 88
}
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
范围(Range)
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。
在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对的 key 值。
package main
import "fmt"
func main() {
// 使用range求一个slice的和
nums := []int{2, 3, 4}
sum := 0
// 使用空白符"_"忽略了序号
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
// range也可以用在map的键值对上
kvs := map[string]string{"a" : "apple", "b" : "banana"}
for k,v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
// range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身
for i, c := range "go" {
fmt.Println(i, c)
}
}
Map
通过[ ]插入修改value,通过delete删除键值对
// 声明变量,默认map是nil
var map_variable map[key_data_type]value_data_type
// 使用make函数
map_variable := make(map[key_data_type]value_data_type)
举例:
package main
import "fmt"
func main() {
// 创建map
countryCapitalMap := map[string]string{"France" : “Paris”, “Italy" : "Rome", "Japan" : ”Tokyo", "India" : "New delhi"}
fmt.Println("原始地图")
// 打印地图
for contry := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
// 删除元素
delete(countryCapitalMap, "France")
fmt.Println("法国条目被删除")
fmt.Println("删除元素后的地图")
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
}
接口(Interface)
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
// 定义接口
type interface_name interface {
method_name1[return_type]
}
// 定义结构体
type struct_name struct {
// variables
}
// 实现接口方法
func (struct_name_variable struct_name) method_name1() [return_type] {
// 方法实现
}
例子:
package main
import (
"fmt"
)
type Phone interface {
call()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
Channel
Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯。
Channel是一个先入先出队列,接收的数据和发送的数据的顺序是一致的。
它的操作符是箭头 <- ,箭头的指向就是数据的流向。
它包含三种类型的定义。可选的<-代表Channel的方向。如果没有指定方向,Channel就是双向的,既可以接收数据,也可以发送数据
chan int // 可以接收和发送类型为int的数据
chan<- float64 // 只可以用来发送float64类型的数据
<-chan int // 只可以用来接收int类型的数据
使用make初始化Channel,并且可以设置容量:
make(chan int, 100)
容量(capacity)代表Channel容纳的最多的元素的数量,代表Channel的缓存的大小。
如果没有设置容量,或者容量设置为0,说明Channel没有缓存,只有sender和receiver的准备好了后,它们的通讯(communication)才会发生。如果设置了缓存,就有可能不发生阻塞,只有buffer满了后send才会阻塞,而只有缓存空了后receiver才会阻塞。一个nil channel不会通信。
例子:
c := make(chan int)
defer close(c) // 类似析构函数
go func() { c <- 3+4 } () // 创建一个goroutine执行匿名函数
i := <-c
fmt.Println(i)
往一个已经被close的channel中继续发送数据会导致run-time panic。
从一个被close的channel中接收数据不会被阻塞,而是立即返回,接收完已发送的数据后会返回元素类型的零值(zero value)。
错误处理
Go语言通过内置的错误接口提供了非常简单的错误处理机制。
error类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
我们可以在编码中通过实现error接口类型来生成错误信息。
函数通常在最后的返回值中返回错误信息。使用error.New可返回一个错误信息:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
}