golang快速入门--语言基础

语言基础语法

行分隔符

  • 在golang中,多个语句写在同一行,必须使用分号 " ; " 分隔开

注释

单行注释

  • 使用// 即可表示

多行注释

  • 使用// 表示

字符串连接

  • 允许使用 + 来拼接字串
  • 使用 fmt.Sprintf 格式化字符串并赋值给新串

关键字(25)

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

预定义标识符

append bool byte cap close complex complex64 complex128 uint16
copy false float32 float64 imag int int8 int16 uint32
int32 int64 iota len make new nil panic uint64
print println real recover string true uint uint8 uintptr

数据基本类型

布尔类型

数字类型

  • int,float32,float64

字符串类型

派生类型

  • 指针类型
  • 数组类型
  • 结构化类型
  • Channel类型
  • 函数类型
  • 切片类型
  • 接口类型
  • Map类型

代码

package main

import "fmt"

func main() {
	var a bool = true // 显式声明变量
	fmt.Println(a)

	b := true // 简写声明变量的方法
	fmt.Print(b)

	var c = true // 定义一个变量,但是不声明类型,系统自己判断
	fmt.Println(c)

	var d = "hello world" // 声明一个字符串
	fmt.Println(d)

	var e *int             // 定义一个指针类型
	var f []int            // 定义一个数组
	var g map[string]int   // 定义一个map
	var h chan int         //  定义一个管道,也就是队列
	var i func(string) int // 定义一个函数
	var j error            // 定义一个错误
	fmt.Printf("格式化输出 = %s\n", e)
	fmt.Printf("格式化输出 = %s\n", f)
	fmt.Printf("格式化输出 = %s\n", g)
	fmt.Printf("格式化输出 = %s\n", h)
	fmt.Printf("格式化输出 = %f\n", i)
	fmt.Printf("格式化输出 = %s\n", j)

	var m, n = 1, "test" // 同时定义多变量
	fmt.Printf("格式化输出m = %c\n", m)
	fmt.Printf("格式化输出n = %c\n", n)
}

值类型和引用类型

  • 像int,float,bool,string等都是值类型,在赋值时,都是额外开辟内存空间,将值赋值过去
  • 而引用类型则存储的是引用处的内存地址

全局变量与局部变量

  • 局部变量申请了就必须用
  • 全局变量申请了,不一定非要用

常量的定义

  • 显式定义常量
  • 隐式定义常量
const s string = "hello world"
const s1 = "hello world"
  • 常量用作枚举类型
package main

import "fmt"

func main() {
	const (
		a = 1
		b = 2
		c = 3
	)
	fmt.Println(a, b, c)
}
  • iota:特殊常量,可以认为是一个可以被编译器修改的常量(const 中每新增一行常量声明将使 iota 计数一次)
package main

import "fmt"

func main() {
	const (
		a = iota
		b
		c = iota
		d = "haha"
		e = iota
	)
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)
	fmt.Println(e)

}
[ ~ ] # go run test.go
0
1
2
haha # 这里也是计数了的
4

运算符

package main

import "fmt"

func main() {
	var a = 1
	var b = 2
	var c int
	// 算术运算符
	fmt.Println("算术运算符...")
	c = a - b
	fmt.Printf(" - 的值为:%d\n", c)
	c = a + b
	fmt.Printf(" + 的值为:%d\n", c)
	c = a * b
	fmt.Printf(" * 的值为:%d\n", c)
	c = a / b
	fmt.Printf(" / 的值为:%d\n", c)
	c = a // b
	fmt.Printf(" // 的值为:%d\n", c)
	c = a % b
	fmt.Printf(" 除法 的值为:%d\n", c)
	c = 2
	c--
	fmt.Printf(" -- 的值为:%d\n", c)

	// 比较运算符
	fmt.Println("比较运算符...")
	a = 1
	b = 2
	if a > b {
		fmt.Println("a > b")
	} else if a < b {
		fmt.Println("a < b")
	} else {
		fmt.Println("a = b")
	}
	if a != 2 {
		fmt.Println("a != 2")
	}
	if a >= 1 {
		fmt.Println("a > = 1")
	}
	if a == 1 {
		fmt.Println("a == 1")
	}
	// 逻辑运算符
	fmt.Println("逻辑运算符...")
	if a == 1 && b == 2 {
		fmt.Println("a ==1 && b == 2")
	}
	if a == 1 || b == 2 {
		fmt.Println("a == 1 || b == 2")
	}
	if !(a == 1) {
		fmt.Println("not a")
	}
	// 位运算符
	fmt.Println("位运算符...")
	var e = a & b
	var f = a | b
	var g = a ^ b
	fmt.Println(e, f, g)
	// 指针运算符
	fmt.Println("指针运算符...")
	fmt.Println(&a)

	// 定义一个指针变量
	var h *int
	h = &a
	fmt.Println(*h)
}

  • 执行
[ ~ ]# go run test.go
算术运算符...
 - 的值为:-1
 + 的值为:3
 * 的值为:2
 / 的值为:0
 // 的值为:1
 除法 的值为:1
 -- 的值为:1
比较运算符...
a < b
a != 2
a > = 1
a == 1
逻辑运算符...
a ==1 && b == 2
a == 1 || b == 2
位运算符...
0 3 3
指针运算符...
0xc000012088
1

if语句与循环语句

package main

import "fmt"

func main() {
	var n = 10
	var i = 0
	for true {
		if i%2 == 0 {
			fmt.Printf("偶数 = %d\n", i)
		} else if i%5 == 0 {
			fmt.Printf("此数为5的倍数 = %d\n", i)
		} else {
			fmt.Println("啥也不是")
		}
		if i == n {
			fmt.Println("已达上限,准备退出")
			break
		}
		i++
	}
}

  • 执行
[ ~ ]# go run test.go
偶数 = 0
啥也不是
偶数 = 2
啥也不是
偶数 = 4
此数为5的倍数 = 5
偶数 = 6
啥也不是
偶数 = 8
啥也不是
偶数 = 10
已达上限,准备退出

函数

func function_name( [parameter list] ) [return_types] {
   函数体
}
  • 标准函数测试
package main

import "fmt"

func add(a int, b int) (res int) {
	// @param     a        int         ""
	// @param     b        int         ""
	// @return    res        int         "返回求和结果"
	res = a + b
	return
}
func div(a int, b int) int {
	// @param     a        int         ""
	// @param     b        int         ""
	// @return            int         "返回差结果"
	var res int
	res = a - b
	return res
}

func main() {
	var a = 2
	var b = 1
	fmt.Println(add(a, b))
	fmt.Println(div(a, b))
}

  • 闭包
package main

import (
	"fmt"
	"math"
)

func get_sqrt() func(v float64) float64 {
	// 返回sqrt处理的函数
	return math.Sqrt
}

func main() {
	var a float64 = 4
	var sqrt = get_sqrt() // 得到一个函数
	fmt.Println(sqrt(a))  // 调用内部函数 输出2
}

数组

  • 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列
    • 例如:[1,2,3]
  • 数组中使用索引下标访问元素
  • 声明数组
// var variable_name [SIZE] variable_type 一维数组
// var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type 多维数组
var a [2] int // 声明数组长度为2个的数组
var b = [2] float32{1,2} // 声明并赋值

var c = [2][1] float64{{1},{2}} // 声明一个二维数组
  • 实例
package main

import "fmt"

func test(arr [][]float64) {
	// 参数为一个二维数组
	fmt.Println(arr)
}

func main() {
	var a = [2]int{1, 2} // [1 2]
	fmt.Println(a)
	fmt.Printf("第二个元素是 %d\n", a[1])
	var b [2]float64 // 声明一个数组,在查看默认值
	fmt.Println(b)

	var c = [2][1]float64{
		{1}, {2},
	}
	test(c)
	
}
[ ~ ]# go run test.go
[1 2]
第二个元素是 2
[0 0]
[[1] [2]]

指针

  • 取变量地址使用&
  • 声明指针和访问指针用*
  • 指针的指针用**表示,访问也是同理
package main

import "fmt"

func changeArr(arr [2]int) {
	// 数组值传递
	arr[0] = 2
}

func changeArrByptr(arr *[2]int) {
	// 数组引用传递
	arr[0] = 2
}

func main() {
	var a int = 1
	fmt.Println(&a)
	var arr = [2]int{1, 2}
	fmt.Printf("改变前:%+v\n", arr)
	changeArr(arr)
	fmt.Printf("改变后:%+v\n", arr)
	changeArrByptr(&arr)
	fmt.Printf("改变后:%+v\n", arr)

}

  • 结果
[ ~ ]# go run test.go
0xc000012088
改变前:[1 2]
改变后:[1 2]
改变后:[2 2]

结构体

  • 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合(应用类型)
  • 而数组表示的是同一类的数据集合
  • 定义结构体
type struct_variable_type struct {
   member definition
   member definition
   ...
   member definition
}
  • 声明结构体
variable_name := structure_variable_type {value1, value2...valuen}
// 或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
  • 实例
package main

import "fmt"

type animals struct {
	// 定义结构体,类似python的类中的属性
	name string
	age  int
	food string
}

func (ani animals) eat() {
	// 为结构体定义方法
	fmt.Printf("%s 吃 %s\n", ani.name, ani.food)
}

func main() {
	var cat animals
	cat.name = "cat"
	cat.age = 1
	cat.food = "猫粮"
	cat.eat()

	var dog animals
	dog.name = "dog"
	dog.age = 1
	dog.food = "狗粮"
	dog.eat()

	cat.eat()

}

  • 结果
[ ~ ]# go run test.go
cat 吃 猫粮
dog 吃 狗粮
cat 吃 猫粮

切片

  • 切片就是动态数组
  • 定义切片
var identifier []type
  • 使用 make() 函数来创建切片
var slice1 []type = make([]type, len)
  • 实例
package main

import "fmt"

func main() {
	var s = make([]int, 3, 5)
	fmt.Println(s)      // 效果跟数组一样
	fmt.Println(cap(s)) // 查看切片的容量
	fmt.Println(len(s)) // 查看切片现在的长度
	s = append(s, 1) // 想切片中追加元素
	fmt.Println(s)
	var s1 = s[2:] // 切片截断
	fmt.Println(s1)
	fmt.Println(cap(s1))
	s1[0] = 10     // 修改切片中第一个元素
	fmt.Println(s) // 结果显示,切片是引用传递

}

  • 结果
[ ~ ]# go run test.go
[0 0 0]
5
3
[0 0 0 1]
[0 1]
3
[0 0 10 1]

Map集合

  • 一种无序的键值对的集合
  • 定义Map
/* 声明变量,默认 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() {
	var m map[string]string
	m = map[string]string{}
	m["name"] = "dog" // 添加值
	m["age"] = "1"
	fmt.Println(m) // map[age:1 name:dog]

	delete(m, "age")
	fmt.Println(m) // map[name:dog]
}

Range范围

  • range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
  • 实例
package main

import "fmt"

func main() {
	var arr = [2]int{1, 2}
	fmt.Println("遍历数组...")
	fmt.Println("索引", "值")
	for i, j := range arr {
		fmt.Println(i, j)
	}
	var s = []int{1, 2, 3}
	fmt.Println("遍历切片...")
	fmt.Println("索引", "值")
	for i, j := range s {
		fmt.Println(i, j)
	}

	var m = map[string]string{"a": "1", "b": "2"}
	fmt.Println("遍历字典...")
	fmt.Println("索引", "值")
	for i, j := range m {

		fmt.Println(i, j)
	}
}

  • 结果
[ ~ ]# go run test.go
遍历数组...
索引 值
0 1
1 2
遍历切片...
索引 值
0 1
1 2
2 3
遍历字典...
索引 值
a 1
b 2

类型转换

type_name(expression)
var s = "1"
var i int
i = int(s)
package main

import (
	"fmt"
	"strconv"
)

func main() {
	var f = 1.3
	var i int
	i = int(f) // 数之间的强转
	fmt.Println(i)

	var s = "1.3"
	i1, err1 := strconv.Atoi(s) // 字符转int
	fmt.Println(i1, err1)       // 0 strconv.Atoi: parsing "1.3": invalid syntax

	i2, err2 := strconv.ParseFloat(s, 10)
	fmt.Println(i2, err2) // 1.3 <nil>
}

语言接口

  • 把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口
  • 实例
package main

import "fmt"

type Phone interface {
	// 定义方法
	call() int
}

type Iphone struct {
	// 定义结构体的属性
	time string
}

func (receiver Iphone) call() int {
	// 定义结构体中的方法
	fmt.Println("Iphone通话中...")
	return 1
}

type Huawei struct {
	time string
}

func (receiver Huawei) call() int {
	fmt.Println("Huawei通话中...")
	return 1
}

func main() {
	var phone Phone = new(Iphone)
	phone.call()
	// fmt.Println(phone.time) // 这里报错,因为Phone为interface

	var huawei Huawei
	huawei.call()
	fmt.Println(huawei.time)
}

  • 结果
[ ~ ]# go run test.go
Iphone通话中...
Huawei通话中...

多态与继承

  • 实例
package main

import "fmt"

type Country struct {
	// 定义一个抽象的结构体,把这个称作基类
	name string
}

func (c Country) language() {
	// 基类的方法
	fmt.Println("有语言")
}

type China struct {
	// 定义一个子类并继承父类
	Country // 继承父类
	culture string
}

func (c China) say() {
	fmt.Println("说中文")
}
func (c China) language() {
	fmt.Println("语言为中文")
}

func main() {
	china := China{Country{name: "中国"}, "文化"}
	china.Country.language() // 父类的方法
	china.language()         // 如果没有重写父类的方法,则调父类方法,否则调子类的方法
	fmt.Println(china)
	fmt.Println(china.name)
	fmt.Println(china.culture)
}

  • 结果
[ ~ ]# go run test.go
有语言
语言为中文
{{中国} 文化}
中国
文化

错误处理

  • 通过内置的错误接口提供了非常简单的错误处理机制
  • defer 延迟函数调用,将需要调用的函数全部压入栈中,在程序结束前或遇到panic时调用的
  • 实例
package main

import (
	"errors"
	"fmt"
)

func er_test() (int, error) {
	// 通常go语言中最后一个参数为错误信息
	if 3 < 2 {
		return 1, nil
	} else {
		return 0, errors.New("比较错误")
	}
}

func recover_func() {
	recover() // 遇到异常,试图恢复程序
}

func main() {
	_, err := er_test() // 显式的获取异常
	if err != nil {
		fmt.Println(err)
		defer recover_func() // 压入栈中,暂时不执行
		fmt.Println("defer被压入栈中,等待执行")
		panic(err) // 主动抛出异常
	} else {
		fmt.Println("么有异常")
	}
	fmt.Println("程序完成")

}

  • 结果
[ ~ ]# go run test.go
比较错误
defer被压入栈中,等待执行

Go并发与管道channel

  • 支持并发,我们只需要通过 go 关键字来开启 goroutine 即可
  • goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的
go 函数名( 参数列表 )
  • 通道(channel)是用来传递数据的一个数据结构,可以理解为就是队列
ch := make(chan int)
ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v
  • 实例
package main

import (
	"fmt"
	"sync"
)

func produce(v int, c chan int) {
	// 构造一个生产者
	fmt.Printf("生产数据 %d\n", v)
	c <- v
}

func consumer(c chan int, wg *sync.WaitGroup) {
	// 消费组
	for true {
		m, ok := <-c
		if ok == true {
			fmt.Printf("消费数据 %d\n", m)
		} else {
			break
		}
	}
	wg.Done() // 该线程完成
}

func main() {
	ch := make(chan int, 5) // 初始化一个管道队列
	var threed_num = 3      // 定义消费者线程数量
	var wg sync.WaitGroup   // 线程控制组
	wg.Add(threed_num)
	for i := 0; i < 5; i++ {
		produce(i, ch) // 同步生产数据
	}
	for i := 0; i < threed_num; i++ {
		go consumer(ch, &wg) // 3个消费者消费数据
	}
	fmt.Println("结束") // 这个可能早于消费者执行完
	close(ch)         // 关闭管道,不在写数据进管道
	wg.Wait()         // 等待线程都结束
	fmt.Println("这个永远最后执行")

}

  • 结果
[ ~ ]# go run test.go
生产数据 0
生产数据 1
生产数据 2
生产数据 3
生产数据 4
结束
消费数据 1
消费数据 3
消费数据 4
消费数据 0
消费数据 2
这个永远最后执行

反射

概念

  • 反射就是有时候你不知道你的参数数据类型是什么,函数方法也不清楚,这时候需要我们反射去调用相应的函数,可以理解为python中的动态导包
  • 反射是通过接口来实现的

语言类型

静态语言
var i int
i = 1 // 是对的
i = "1" // 错的类型错误
// 静态语言就是刚开始声明时就决定了其类型,不可更改
动态语言
var i interface{}
i = 1 // 是对的,此时的类型为int
i = "1" // 也是对的,此时的类型为string
// 动态类型是可以随时更改的
reflect包
  • 通过包来反射数据类型
package main

import (
	"fmt"
	"reflect"
)

func fmt_reflect(i interface{}) {
	t := reflect.TypeOf(i)  // 获取数据类型
	v := reflect.ValueOf(i) // 获取数据值
	fmt.Println(t)
	fmt.Println(v)
	fmt.Println(t.Name() == "string") // 获取类型名称以及种类
	fmt.Println(t.Kind() == reflect.String)

}

func reflect_test_func() {
	fmt.Println("reflect")
}

type ReflectTest struct {
}

func (receiver ReflectTest) method_test() {
	fmt.Println("method_test")
}

func main() {
	var i interface{} // 声明动态类型
	i = 1             // 先定义为int
	fmt_reflect(i)
	i = "a" // 换为string
	fmt_reflect(i)
	f1 := reflect.ValueOf(reflect_test_func) // 反射函数
	f1.Call(nil)                             // 回调该函数
	t := ReflectTest{}
	t.method_test()
	f2 := reflect.ValueOf(t).MethodByName("method_test") // 反射结构体,并获取其方法
	fmt.Println(f2)
	f2.Call(nil) // 回调该方法
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值