一、指针
//指针 获取对象、变量的内存地址
//取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
//指针类型前面加上 * 号(前缀)来获取指针所指向的内容
func pointDef() {
//定义指针变量
var ip *int /* 指向整型*/
//获取变量地址
a := 1
fmt.Println("变量的内存地址:", &a)
//通过指针变量访问目标地址
ip = &a
fmt.Println("ip变量的目标指针存储地址:", ip)
fmt.Println("ip指针所指向的内容:", *ip)
//空指针
var ptr *int
if (ptr == nil) {
fmt.Printf("ptr 为空指针,值为 : %x\n", ptr)
}
//向函数传递指针
b := 2
var x *int
var y *int
x = &a
y = &b
//传入指针 值分别为1 2
swap(x, y)
}
//指针传入函数
func swap(x *int, y *int) {
var temp int
//指针传值
temp = *x //x指针指向的值赋值给tmp
fmt.Println("temp:", temp)
*x = *y //y指针指向的值,赋值给x指针
fmt.Println("*x:", *x)
fmt.Println("x赋值给y前,y地址:", y)
*y = temp //temp 赋值给y值
fmt.Println("*y:", *y)
//打印指针指向地址
fmt.Println("x地址:", x)
fmt.Println("y地址:", y)
}
二、结构体
//声明结构体; 等同java 对象
type Book struct {
title string
author string
}
func stuctDef(){
//实例化book
var goBook Book
goBook.title = "Go"
goBook.author = "Max"
//book属性引用
fmt.Println(goBook.title)
}
三、range遍历
//range 数组 ,用于遍历圈定遍历范围
func rangeDef() {
//准备一个slice数组
nums := []int{2, 3, 4}
sum := 0
//利用range遍历数组进行求和;_ 表示不用关注循环的i次数
for _, num := range nums {
if num == 3 {
fmt.Println("range中做判断", 3)
}
sum += num
}
fmt.Println("sum:", sum)
//利用range 遍历map的kv
//声明一个map
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
}
四、集合 map
func mapDef() {
//创建map
goMap := make(map[string]string)
goMap["key1"] = "go1"
goMap["key2"] = "go2"
goMap["key3"] = "go3"
//创建map
goMap2 := map[string]string{"1": "1", "2": "2", "3": "3"}
for v := range goMap2 {
fmt.Println(v)
}
//遍历map kv
for name := range goMap {
fmt.Println(name)
}
for k, v := range goMap {
fmt.Println("k:", k, "v:", v)
}
//删除key
delete(goMap, "key1")
//遍历 输出key
for key := range goMap {
fmt.Println(key, "key is", goMap [ key ])
}
}
五、接口定义
import "fmt"
//定义接口
type VowelsFinder interface {
FindVowels() []rune
}
type MyString string
//实现接口
func (ms MyString) FindVowels() []rune {
var vowels []rune
for _, rune := range ms {
if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' {
vowels = append(vowels, rune)
}
}
return vowels
}
func main() {
name := MyString("Sam Anderson") // 类型转换
// 调用接口
var v VowelsFinder
v = name
fmt.Printf("Vowels are %c", v.FindVowels())
}
六、并发
goroutine是通过Go的runtime管理的一个线程管理器,通过关键字go就启动了一个goroutine(一个线程)。
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("hello") //开一个新的Goroutines执行
say("world") //当前Goroutine执行
}
可以测试把main中的go关键字去掉zaiz在执行,此时的say("hello")和say("world")则开始串行执行。证明采用go关键字,确实新起了一个线程并行打印hello world。
七、反射
熟悉java的coder,反射肯定都烂熟于心了,go的反射也同理,不过要注意,go反射的字段一定是可读写的,比如下例,拿一个4的int常量值来反射修改成8,会报错。而应该拿到x=4中x的内存地址进行修改。要修改的是变量内存指向8,而数值本身是4就是4,是不可写的。
//反射
func reflectDef() {
x := 4
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
//v.SetInt(8) //报错 反射的字段必须是可读写的
//改写成
p:=reflect.ValueOf(&x) //拿到x变量的内存地址
v2:=p.Elem() //赋值给v2 再修改v2
v2.SetInt(8)
fmt.Println("反射获取变量类型为:",t)
fmt.Println(v)
fmt.Println("反射修改v的值为:",v2)
}