go语言学习笔记 之 go语言基础

环境配置

  • GOROOT:SDK的安装路径
  • PATH:添加$GOROOT/bin
  • GOPATH:项目的目录(工作环境)

变量声明

// 先声明再赋值
var v1 int
v1 = 1

// 声明且赋值
var v2 = 2

// 声明且赋值2
v2_1 := 21

// 多变量赋值
var v3,v4,v5 = 3,"abc",5.0
// 多变量赋值2
v3_1,v4_1,v5_1 := 3,"abc",5.0

// 多变量声明
var v6,v7,v8 int

// 全局变量声明方式
var(
	v9 = 100
	v10 = "global"
	v11 = 1.1
)

类型转换

var i int32 = 0
// int32 -> float
var fi float32 = float32(i)
// int32 -> int8
var i8 int8 = int8(i)
// int32 -> int64
var i64 int64 = int64(i)

// float -> string
var str string
str = fmt.Sprintf('%f',fi)
// 转字符串
strconv.Itoa(8)

// bool -> string
var b bool = true
str = fmt.Sprintf('%t',b)

// 另一种方式转成字符串
str = strconv.FormatInt(int64(i8), 10)
// 转数值
strconv.Atoi("8")

// string -> bool
// 转换失败会赋一个默认值
b, _ = strconv.ParseBool(str) // 这里忽略error

指针

  1. 基本数据类型,变量存的就是值
  2. 获取变量的地址用&
  3. 指针类型,变量存的是一个地址,这个地址指向的空间才是实际值
  4. 获取指针类型所指向的值用*

指针、slice切片、map、管道channel、interface等都是引用类型,调用方法时传递的是引用

// i的地址是 &i
var i int = 123

// 指针声明,将i的地址给p指针
// 注意:指针和实际类型必须一致
var p *int = &i

// 从指针获取i的值
var i2 int = *p

// str -> array
[]byte("hello world")
// array -> str
string([]byte("123"))

标识符命名

采用驼峰命名,如果首字母大写则其他的包也能访问,如果首字母大写则只能本包访问。

引入包和go path变量有关,引入时取包的绝对路径删除$GOPATH/src/前缀

进制

  • 0开头是8进制
  • 0x开头是16进制
  • 正常是10进制
  • 不支持写2进制

switch

var age int = 18
switch {
	case age < 18:
		fmt.Println("未成年")
		fallthrough // 穿透到下一层
	case age >= 18:
		fmt.Println("成年人")
	default:
		fmt.Println("年龄不正常")
}

// type switch可以用来判断某个interface变量中实际指向的变量类型
var x interface{}
var y = 101
x = y
switch i := x.(type) {
	case nil:
	fmt.Printf("x的类型是%T",i)
	case int:
	fmt.Printf("x是int型")
	case float64:
	fmt.Printf("x是float64型")
	case func(int) float64:
	fmt.Printf("x是func(int)型")
	case bool, string:
	fmt.Printf("x是bool或string型")
	default:
	fmt.Printf("未知")
}

遍历

// 死循环
for {
}
// 布尔表达式循环
for true {
}
// 常规循环
for i := 0;i < 10; i++ {
}
// for range循环
for idx, val := range str{
}

在低版本的go sdk中如果str中有中文,使用range遍历没问题,使用传统遍历方式把str作为数组遍历可能会导致输出结果乱码,可以将string转换成rune在遍历:[]rune(str)

函数

基本语法
func 函数名(形参列表)(返回值列表){
	函数体
	return 返回值
}

// 传递的是指针,*int是指针类型
func test(num *int) {
	// 这里的 *num是num的实际值,是从num这个指针指向的地址取值
	*num = *num + 10
}

func sum(a int,b int) int{
	return a + b
}

// go语音的函数式
func useFunc(f func(int,int) int, a int, b int) int {
	return f(a,b)
}
// 可以使用type简化func的写法(新版可能有问题)
type myFunc func(int,int) int
func useFunc(f myFunc, a int, b int) int {
	return f(a,b)
}

// 调用可以这么玩
var mySum = sum
result := useFunc(sum,10, 20)

// 返回多个结果可以只要名称对应,return省略
func f(a int,b int)(sum int, sub int){
	sum = a + b
	sub = a - b
	return
}
  • init函数是特殊的函数,在运行时会最先被调用
  • 匿名函数
    sumResult := func (a int, b int) int {
    	return a + b
    }(10,20)
    
    secondFunc := func (a int, b int) int {
    	return a + b
    }
    secondSumResult := secondFunc(10,20)
    
    
  • 闭包:一个使用外部变量的函数
    // 返回一个n+a的函数,类似class
    // 注意:这个返回的函数如果多次使用,n会变
    // 好处是n传入一次,就可以反复使用
    func sum(n int) func(int) int {
    	return func(a int) int {
    		n += a
    		return n
    	}
    }
    
  • defer:延迟执行某些操作,会将defer行的操作按照先后顺序压入栈中,等函数执行完毕后,会根据入栈的顺序先后执行,类似对整个函数加了一个final,defer操作行的变量会拷贝一份,函数中修改对defer不生效

  • 引入写的是路径
  • 使用写的是package

一般要求路径的最后一级与package名称一致

// 比如在abc/bcd/efg
package test
// ....代码省略

// 另一个包使用test的函数
package main
import (
	// 引入刚刚的模块
	"abc/bcd/efg"
)

// 使用
test.Xxx()

// 还可以使用别名的方式使用
package main
import (
	t "abc/bcd/efg"
)

// 使用
t.Xxx()

内置函数

// new函数用来分配内存,主要分配值类型 ,返回的是一个指针
iptr := new(int)
// make函数用来分配内存,主要分配引用类型
make()

// 类型断言
var a interface{}
var b Cat = Cat{}
a = b
var c Cat
c = a.(Cat) // 此处为类型断言,如果类型一致则转换成功,如果类型不一致则抛出异常
c, ok = a.(Cat) // 此处为带检测类型断言,类型不一致也不会抛出异常

// 关闭函数,用来关闭管道
myChan := make(chan int, 10)
close(myChan)

异常处理

// defer + recover
// 这个代码放到函数中,会在函数运行结束之后运行
// 如果有异常会捕获到,并打印出来
defer func(){
	err := recover()
	if err != nil {
		fmt.println(err)
	}
}

// 自定义异常
myErr := errors.New("index out of array")
// panic函数如果参数为异常,则打印错误并终止程序
panic(myErr)

数组

// 声明数组
var arr1 [2]int
// 使用数组
arr1[0] := 1
arr1[1] := 1

// 数组的其他使用方式
var arr2 [2]int = [2]int {1, 2}
// 三个点表示填充后面的元素个数,可以省略
var arr3 = [...]int {1, 2}
// 使用对应下标初始化
var arr4 = [2]string{1:"张三", 0:"李四"}

// go中数组的引用传递
func test(arr *[3]int){
	// 使用时加*取实际值
	(*arr)[0] = 10
}

// 切片slice,使用数组初始化
// 将arr中1和2元素取出,生成切片
// arr[0:3] 等价于 arr[:3]
// arr[2:len(arr)] 等价于 arr[2:]
// arr[0:len(arr)] 等价于 arr[:]
slc := arr[1:3]
fmt.Println("切片中的元素个数:",len(slc))
fmt.Println("切片中的容量:",cap(slc))
// 有趣的是下面,这个是true,也就是说切片中存储的是数组中元素的地址
fmt.Println(&slc[0] == &arr[1])

// 切片的初始化方式,4是长度,10是容量(可选)
var s1 []int = make([]int,4,10)
var s2 []int = []int{1,2,3}

// 添加数据
s2 = append(s2,4,5,6)
// 三个点表示将slice打散传入
s2 = append(s2,s2...)

// 复制
copy(s2,s1)

// 二维数组
var aa1 [3][4]int = [3][4]int{{1,2,3,4},{},{}}
var aa2 = [3][4]int{{1,2,3,4},{},{}}

map

// map的key可以是bool,数字,string,指针,channel,接口,结构体,数组
// 注:slice、map和func不可以用
// key为int,值也为int
var m map[int]int
// key为int,值为(key为int和value为int)的map
var m map[int]map[int]int
// 使用前必须要先进行make分配空间,大小为选填
m = make(map[int]map[int]int, 16)

// 或者直接赋值,内部元素必须以逗号结尾
m1 := map[int]int{
	1:1,
	2:2,
}

// 删除某元素操作
delete(m1, 1)

// 查询操作,第一个返回值为该key的值,第二个元素为是否存在 
val, ok := m1[2]

// 遍历
for k,v := range m1 {

}

面向对象

// 结构体是值类型,变量赋值给另一个变量会完全拷贝
type Cat struct{
	Name string
	Age int
	Color string
}

// 结构体的使用
c := Cat{}
c := Cat{"name",1,"color"}
var c *Cat = new(Cat)
var c *Cat = &Cat{}
(*c).Name = "aaa"
// 赋值也可以使用下面的赋值
c.Name = ""
c.Age = 12

// 字段和类型完全相同的两个结构体可以互相转换,强转
// 结构体声明之后的内存分配基本是连续的
// 可以这样声明,相当于取了一个别名
type C Cat

// json转换时,因为作用域的原因,只能转换首字母大写的字段
// 解决方案:
type Person struct{
	Name string `json:"name"`
	Age int `json:"age"`
}

方法

方法只存在于结构体中,声明方式类似于函数,但是在go中函数和方法不是一个东西

type A struct{
	Name string
}

// 这里是传值,会将调用该方法的复制一份传入该方法
// 参数可以使用args ...in传入不定长参数
func (a A) aTest(){
	
}

// 特殊的方法
// String() -> print会默认调用该方法

继承

使用匿名嵌套结构体表达继承

  • 结构体可以使用匿名嵌套结构体的所有字段和方法,不论是首字母大写还是小写
  • 如果嵌套的多个结构体(多重继承)有相同的方法和字段,使用时需要指定到底要用谁的方法和字段,否则编译器会报错
type Goods struct{
	Name string
	Price float64
}

type Book struct {
	Goods // 嵌套匿名结构体
	Writer string
}

// 使用
book := &Book{}
book.Writer = "张三"
book.Goods.Name = "书"
book.Goods.Price = 128.0
// 也可以这样用,取值优先级是 本结构体 > 嵌套结构体
book.Name = "go语音从入门到放弃"
book.Price = 100000000000.00

接口

接口实现不需要显示指定,只有实现了接口所有方法,才会被认为是实现了该接口
基本语法

type 接口名 interface {
	方法1(参数列表) 返回值
	方法2(参数列表) 返回值
}
type Usb interface {
	Start()
	Stop()
}

type Phone struct {

}
func (this Phone) Start(){
	fmt.Println("手机开始工作")
}
func (this Phone) Stop(){
	fmt.Println("手机停止工作")
}

type Camera struct{

}
func (this Camera) Start(){
	fmt.Println("相机开始工作")
}
func (this Camera) Stop(){
	fmt.Println("相机停止工作")
}

type Computer struct {

}

func (this Computer) Work(usb Usb){
	usb.Start()
	usb.Stop()
}

func main(){
	// 使用方式如下
	p := Phone{}
	computer := Computer{}
	computer.Work(p)
}

多态

go语言使用接口实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值