基础语法学习
前言
这个是个人结合狂神说的视频以及 G o B y E x a m p l e Go \ By \ Example Go By Example来做的结合文件,如果需要学习 G o Go Go的话个人强烈建议去 G o G u i d e Go \ Guide Go Guide学习
相关链接如下:
Go by Example 中文版 (gobyexample-cn.github.io)
注释
package main
import "fmt"
//我是单行注释
/*
我是多行注释
*/
func main() {
fmt.Println("Hello,world")
}
变量
变量是一个没有注释值并且可以随时改变的数值
变量的定义
在go语言中我们声明一个变量一般使用一个var
关键字:
var name type
- 第一个var是声明变量的关键字,是固定的写法
- 第二个name是我们变量的名字
- 第三个type是用来代表变量的类型
var name string = "Treasure"
var age int = 114514
在对于多个变量进行定义的时候我们可以使用如下的方法
func main() {
//使用var关键字来定义
var (
name string
age int
addr string
)
fmt.Println(name, age, addr)
}
- 整型和浮点型变量的默认值为0 和0.0
- 字符串变量的默认值是空字符串
- 布尔类型变量默认是false
- 切片、函数、指针变量默认是null
变量的初始化
变量初始化的标准格式
var 变量名 类型 = 值(表达式)
那么我们在定义的时候可以这么表示
name = "Treasure"
age = 20
addr = "hznu"
短变量声明并且初始化
name := "treasure"
age := 20
fmt.Println(name, age)
fmt.Printf("%T,%T", name, age)
这是go语言中的推导声明写法,编译器会自动根据右值推断出左值的对应类型
它可以自动推导出一些类型,虽然使用时有限制的:
- 定义变量,同时显式初始化
- 不能提供数据类型
- 只能用在函数内部不能随便导出定义
但是我们不能定义之后再短变量声明
var name string
name := "treasure"
这样子时错误的捏
内存地址
var num int
num = 18
fmt.Printf("num:%d,address:%p\n", num, &num) //取地址符时&
num = 114514
fmt.Printf("num:%d,address:%p\n", num, &num)
num:18,address:0xc00001a0a8
num:114514,address:0xc00001a0a8
变量的交换
go变量交换很快直接交换即可
package main
import "fmt"
func main() {
a := 5
b := 4
a, b = b, a
fmt.Println(a, b)
}
匿名变量
匿名变量的特点是一个下划线_
,_
本身就是一个特殊的标识符,被称为空白标识符。在赋值的时候我们可以使用下划线_
来去替没有用的一些变量等
匿名变量是不占用空间的
package main
import "fmt"
func test() (int, int) {
return 100, 200
}
func main() {
a, _ := test()
_, b := test()
fmt.Println(a, b)
}
变量的作用域
一个变量在程序中都有一定的作用范围,称之为作用域
局部变量
声明在函数体内的,优先使用这个函数体内命名的变量
全局变量
声明在外面的可以被所有函数所使用的
常量
注意常量实际上不能被修改,使用const前缀即可
const URL = "acm.hznu.edu.cn"
const URL2 string = "acm.hznu.edu.cn"
iota
特殊常量,可以被认为是一个可以被编译器修改的常量。iota是go语言的常量技术其
iota在const关键字出现的时候就被重置为0,const每新增一行常量声明将会使得iota计数一次
package main
import "fmt"
func main() {
const (
a = iota
b = iota
c = iota
)
fmt.Println(a, b, c)
}
比如说对于这一段代码来说输出的a,b,c就是0,1,2
const (
a = iota
b
c
)
如果是这一个部分的话那么其实常量没用定义的情况下会沿用上面这个常量来使用
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "haha" //haha iota3
e //haha iota4
f = "100" //100 iota 5
g // 100 iota6
h = iota //iota7
i //iota8
)
fmt.Println(a, b, c, d, e, f, g, h, i)
}
0 1 2 haha haha 100 100 7 8
上面这一部分代码很显然沿用了iota
平时使用iota并不多
数值类型
布尔型
布尔类型只有true 或者是false
func main() {
var isFlag bool = true
isOk := false
fmt.Println(isFlag, isOk)
}
true false
数值型
整型int和浮点型float32,float64,Go语言支持整型和浮点型数字并且支持
func main() {
//定义一个整型
//byte uint8
//rune int32
//int int64
var num int = 18
fmt.Printf("%T %d\n", num, num)
//默认是6为小数打印,保存丢失精度是四舍五入的
var now float32 = 1145.14
fmt.Printf("%T %.2f", now, now)
}
int 18
float32 1145.14
字符串类型
单引号也就是字符,双引号仍然是一个字符串
func main() {
var str string = "namomo"
str = "namo"
fmt.Printf("%T %s\n", str, str)
v1 := 'a'
v2 := "a"
fmt.Printf("%T %c\n", v1, v1)
fmt.Printf("%T %s\n", v2, v2)
}
字符串拼接的话仍然可以使用+
来拼接字符
fmt.Println("hello " + str)
对于转义字符的话我们可以使用转移符号\
fmt.Println("hello\" " + str)
数据类型转换
go语言并不存在隐式类型转换,因此所有的类型都必须显式的声明
valueoftypeB = typeB(valueoftypeA)
package main
import "fmt"
// 类型转换
// 转换后的变量 := (要转换的类型)(变量)
// 备注:整型不能转换成为bool
func main() {
a := 3 //int
b := 5.0 //float64
c := float32(a) //float 32
d := int(b)
//整型是不能转换成为bool类型的
//e := bool(a)
fmt.Printf("%t %f %f %d\n", a, b, c, d)
}
运算符
算数运算符
我们假设A = 10,B = 20
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A + B = 30 |
- | 相减 | A - B = -10 |
* | 相乘 | A * B = 200 |
/ | 相除 | B / A = 2 |
% | 求余 | B % A = 0 |
++ | 自增 | A++ = 11 |
– | 自减 | A-- = 9 |
var a, b int = 10, 20
c := a + b
fmt.Println(c)
c = a - b
fmt.Println(c)
c = a * b
fmt.Println(c)
c = a / b
fmt.Println(c)
c = a % b
fmt.Println(c)
c++
fmt.Println(c)
同时注意如果a < b去进行除法的话也是进行整除
关系运算符
我们假定A = 10,B = 20
运算符 | 描述 | 实例 |
---|---|---|
== | False | |
!= | True | |
> | False | |
< | True | |
>= | Flase | |
<= | True |
package main
import "fmt"
func main() {
var a int = 11
var b int = 10
fmt.Println(a == b)
fmt.Println(a != b)
fmt.Println(a > b)
fmt.Println(a < b)
fmt.Println(a >= b)
fmt.Println(a <= b)
}
false
true
true
false
true
false
逻辑运算符
假定A的值为True,B的值为False
运算符 | 描述 | 实例 |
---|---|---|
&& | (A && B)为false | |
|| | (A || B)为True | |
! | !(A && B) 为True |
位运算符
A 为60 ,B为13
运算符 | 描述 | 实例 |
---|---|---|
& | 双目运算符,都是1结果为1否则为0 | |
| | 双目运算符,有1出1,全0出0 | |
^ | 不同时则为1否则为0 | |
&^ | 位清空,a &^ b,对于b上的每个数值,如果为0,则取a对应的数值,如果是1,就取0 | (A &^ B = 48) |
<< | 左移 | |
>> | 右移 |
package main
import "fmt"
func main() {
a := 60
b := 13
var c int
c = a & b
fmt.Println(c)
c = a | b
fmt.Println(c)
c = a ^ b
fmt.Println(c)
c = a &^ b
fmt.Println(c)
}
12
61
49
48
赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 同c一样 | |
+= | ||
-= | ||
*= | ||
/= | ||
%= | ||
<<= | ||
>>= | ||
&= | ||
^= | ||
|= |
package main
import "fmt"
func main() {
a := 21
var b int
b = a
fmt.Println(b)
b += a
fmt.Println(b)
b -= a
fmt.Println(b)
b *= a
fmt.Println(b)
b /= a
fmt.Println(b)
b %= a
fmt.Println(b)
b = 10
b >>= 2
fmt.Println(b)
b <<= 2
fmt.Println(b)
}
键盘输入输出
package main
import "fmt"
func main() {
var x int
var y float64
//定义了两个变量,想用键盘来录入
//fmt.Println() 打印并且换行
//fmt.Printf() 格式化输出
//fmt.Print() 打印输出
fmt.Scanln(&x, &y) //在换行符上停止
fmt.Printf("%d %f\n", x, y)
fmt.Scanf("%d %f", &x, &y) //和正常的scanf差不多
fmt.Printf("%d %f\n", x, y)
fmt.Scan(&x, &y) //一直读取,直到空格或者换行符为止
fmt.Printf("%d %f\n", x, y)
//fmt.Scan()
}
流程控制
程序的流程一共有三种:顺序结构、选择结构以及循环结构
顺序结构:从上到下逐行执行。
选择结构:条件满足某些代码才会执行
- i f if if
- s w i t c h switch switch
- s e l e c t select select
循环结构:条件满足某些代码会被反复执行 0 − N 0 - N 0−N次
- f o r for for
if语句
package main
import "fmt"
func main() {
a := 100
if a >= 90 && a <= 100 {
fmt.Println("A")
} else if a >= 80 {
fmt.Println("B")
} else if a >= 70 {
fmt.Println("C")
} else if a >= 60 {
fmt.Println("D")
} else {
fmt.Println("E")
}
}
if还可以嵌套一个if
package main
import "fmt"
func main() {
var a, b string
pwd := "114514"
fmt.Scan(&a, &b)
if a == pwd {
if b == pwd {
fmt.Println("OK")
} else {
fmt.Println("NOT")
}
} else {
fmt.Println("NOT")
}
}
switch
package main
import "fmt"
func main() {
score := 98
switch score {
case 90:
fmt.Println("A")
case 80:
fmt.Println("B")
case 50, 60, 70:
fmt.Println("C")
default:
fmt.Println("D")
}
}
具体匹配某一个具体的数值但是不是区间
switch可以使用fallthrough 强制执行后面的case语句
package main
import "fmt"
func main() {
a := false
switch a {
case false:
fmt.Println("false")
fallthrough //可以进行case穿透,不管下一个条件是否满足
case true:
if a == false {
break
}
fmt.Println("true")
}
}
循环
正常的循环方式
func main() {
sum := 0
for i := 1; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}
参数是全局变量的时候可以这么写
package main
import "fmt"
func main() {
sum := 0
i := 1
for i <= 10 {
fmt.Println(i)
sum += i
i++
}
fmt.Println(sum)
}
或者我们可以直接写死循环
func main() {
sum := 0
i := 1
for {
fmt.Println(i)
i++
}
fmt.Println(sum)
}
循环实际上和 C P P C\!P\!P CPP几乎差不多,同样的我们可以采用 b r e a k break break和 c o n t i n u e continue continue适度的来结束所有循环或者停止单词循环
string
一般来说我们可以调用各种函数来正常使用除此之外不能直接修改 s t r str str的某个数值
package main
import "fmt"
func main() {
str := "hello"
fmt.Println(str)
//获取字符串的长度为
fmt.Println("the length of string is ", len(str))
//获取对应的字节
fmt.Println("the first obj is", str[0])
fmt.Printf("the first obj is %c\n", str[0])
for i := 0; i < len(str); i++ {
fmt.Printf("the obj is %c\n", str[i])
}
//输出的对应的是下标和字符,遍历数组以及切片的时候可以使用
// 返回下标以及对应的数值,我们直接使用这个数值即可
for i, v := range str {
fmt.Printf("%d %c\n", i, v)
}
//str不能被修改
//str[2] = 'A'
}
函数
- 函数是最基本的代码块用于执行一个任务
- G o Go Go语言至多有一个 m a i n main main函数
函数的声明
G o Go Go语言函数定义格式如下:
func function_name([parameter list])[return_types]{
函数体
}
- 无参无返回值函数
- 有一个参数的函数
- 有两个参数的函数
- 有一个返回值的函数
- 有多个返回值的函数
根据如下代码我们就可以写出一个相加相减的函数
package main
import "fmt"
func main() {
c, d := add(1, 2)
fmt.Println(c, d)
}
// func 函数名(参数) 函数调用后的返回值 函数体
func add(x, y int) (int, int) {
return x + y, y - x
}
package main
import "fmt"
func main() {
//函数的调用
printinfo()
myprint("namomo")
secondprint("namo", "namo")
fmt.Println(add(1, 3))
fmt.Println(mul(3, 5))
}
// 无参无返回值函数
func printinfo() {
fmt.Println("hahahah1")
}
// 有一个参数的函数
func myprint(msg string) {
fmt.Println(msg)
}
// 有两个参数的函数
func secondprint(msg1, msg2 string) {
fmt.Println(msg1 + msg2)
}
// 有一个返回值的函数
func add(x, y int) int {
return x + y
}
// 有多个返回值的函数
func mul(x, y int) (int, int) {
return x + y, x * y
}
hahahah1
namomo
namonamo
4
8 15
函数的形参和函数的实参
package main
import "fmt"
func main() {
a := max(1, 2)
fmt.Println(a)
}
// max 两个参数比较大小
// 形式参数就是传进去的x y
// 实际参数就是调用函数时传给形参的实际数据叫做实际参数
func max(x, y int) int {
if x > y {
return x
} else {
return y
}
// 一个函数定义上有返回值那么函数中必须使用return语句
// 返回值
// 调用处需要使用变量接收该结果
}
可变参数
- 可变参数要放在其他参数的后面
- 一个函数列表中最多只能有一个可变参数
package main
import "fmt"
func main() {
fmt.Println(getsum(3, 4, 5, 6))
fmt.Println(getsum(3, 4, 5))
}
// ...代表可变参数
func getsum(nums ...int) int {
sum := 0
for i := range nums {
sum += nums[i]
}
return sum
}
参数传递
按照数据存储特点来分:
- 值类型的数据:操作的是数据本身 i n t , s t r i n g , b o o l , f l o a t 64 , a r r a y . . . . . . int,string,bool,float64,array...... int,string,bool,float64,array......
- 引用类型的数据:操作的是数据的地址 s l i c e , m a p , c h a n . . . . . . slice,map,chan...... slice,map,chan......
package main
import "fmt"
func main() {
//值传递
//定义一个数组 [个数]类型
//arr2与arr1占用空间不同,arr是数据的副本,修改数据对原始的数据没有影响
arr := [4]int{1, 2, 3, 4}
fmt.Println(arr)
update(arr)
fmt.Println(arr)
//引用传递
//切片 可以扩容的数组
s1 := []int{1, 2}
//s3 := []int{}
fmt.Println("s1", s1)
//传入的是引用类型的数据,地址,所以在函数中更改这个切片在外面也会更改
update2(s1)
fmt.Println(s1)
}
func update(arr2 [4]int) {
arr2[0] = 5
//return arr2
}
func update2(s2 []int) {
fmt.Println("input", s2)
//s2 = append(s2, 10)
s2[0] = 115414
fmt.Println("output", s2)
}
函数中变量的作用域
作用域:变量可以使用的范围
局部变量:函数内部定义的变量,叫做局部变量
全局变量:函数外部定义的变量,叫做全局变量
package main
import "fmt"
// 全局变量在哪里使用
var num int = 100
func main() {
//函数体内的局部变量
temp := 1000
//if for中的都是局部变量只能在自己的循环语句中使用
if b := 1; b <= 10 {
//语句内的局部变量
temp := 50
fmt.Println(temp)
fmt.Println(b) //局部变量就近原则
}
fmt.Println(temp)
fmt.Println(num)
}
func f1() {
a := 1
fmt.Println(a)
fmt.Println(num)
}
func f2() {
//不能使用在其他函数中定义的变量
//fmt.Println(a)
fmt.Println(num)
}
递归函数
一个函数自己调用自己就叫递归函数
递归函数要给自己设置一个出口不然最后就会死循环
package main
import "fmt"
func main() {
fmt.Println(fib(5))
}
// 0 1 2 3 4 5
// 1 1 2 3 5 8
func fib(x int) int {
if x == 1 || x == 0 {
return 1
} else {
return fib(x-1) + fib(x-2)
}
}
defer函数
d e f e r defer defer语义:推迟,延迟
在 g o go go语言中使用 d e f e r defer defer关键字可以来延迟一个函数或者方法的执行
结束完所有的东西之后再来 d e f e r defer defer
如果有多个 d e f e r defer defer语句的话我们可以按照入 d e f e r defer defer栈的顺序去输出
package main
import "fmt"
func main() {
f("1")
defer f("3")
f("5")
defer f("4")
}
func f(s string) {
fmt.Println(s)
}
函数的数据类型
本质都是 f u n c func func,像下列代码如果把 f 11 f11 f11赋值给 f 5 f5 f5的话相当于他们两个函数都用同一个地址里面的东西
package main
import "fmt"
// func 本身就是一个数据类型
func main() {
//不加括号是直接看这个函数,输出的是一个func
fmt.Printf("%T", f11)
var f5 func(int, int)
f5 = f11
f5(1, 2)
}
func f11(a, b int) {
fmt.Println("namo")
//return a + b
}
匿名函数
package main
import "fmt"
func main() {
f1()
f2 := f1 //函数本身也是一个变量
f2()
//匿名函数
f3 := func() {
fmt.Println("im f3")
}
f3()
ha := func(a, b int) int {
fmt.Println(a, b)
fmt.Println("im f4")
return a + b
}(1, 2) //函数本身可以调用自己
fmt.Println(ha)
}
func f1() {
fmt.Println("im f1")
}
回调函数
高阶函数:根据 g o go go语言的数据类型特点,可以将一个函数作为另外一个函数的参数
f u n 1 ( ) , f u n 2 ( ) fun1(),fun2() fun1(),fun2()
将 f u n 1 ( ) fun1() fun1()函数作为 f u n 2 ( ) fun2() fun2()这个函数的参数
f u n 2 fun2 fun2函数:叫做高阶函数。接收了一个函数作为参数的函数
f u n 1 fun1 fun1函数:叫做回调函数,作为另外一个函数的参数
package main
import "fmt"
func main() {
r2 := oper(3, 4, add)
fmt.Println(r2)
r2 = oper(3, 4, sub)
fmt.Println(r2)
r4 := oper(8, 8, func(a, b int) int {
if b == 0 {
fmt.Println("not 0")
return 0
}
return a / b
})
fmt.Println(r4)
}
func oper(a, b int, fun func(int, int) int) int {
r := fun(a, b)
return r
}
func add(a, b int) int {
return a + b
}
func sub(a, b int) int {
return a - b
}
闭包
package main
import "fmt"
/*
一个外层函数中有内层函数,在内层函数中会操作外层函数的局部变量
并且该外层函数的返回值就是这个内层函数
那么这个内层函数和外层函数的局部变量就称为闭包结构
局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用
*/
func main() {
r1 := incre()
fmt.Println(r1)
v1 := r1()
fmt.Println(v1)
v2 := r1()
fmt.Println(v2)
fmt.Println(r1())
fmt.Println(r1())
fmt.Println(r1())
//
r2 := incre()
fmt.Println("r2:", r2)
v3 := r2()
fmt.Println(v3)
fmt.Println(r1())
fmt.Println(r2())
}
func incre() func() int {
i := 0
fun := func() int { //内层函数并没有执行
i++
return i
}
return fun
}
数组
数组是一个具有编号并且长度固定的元素序列
这里我们需要注意几个点,一个是数字通用的从 0 0 0开始,一个是我们可以用内置函数 l e n len len获取 a a a的长度
package main
import "fmt"
func main() {
var a [5]int
fmt.Println("begin:", a)
a[4] = 100
fmt.Println("get a_4", a[4])
fmt.Println("after:", a)
b := [5]int{1, 2, 3, 4}
fmt.Println(b)
var mp [3][3]int
for i := 0; i <= 2; i++ {
for j := 0; j <= 2; j++ {
mp[i][j] = i + j
}
}
fmt.Println("mp->", mp)
}
begin: [0 0 0 0 0]
get a_4 100
after: [0 0 0 0 100]
[1 2 3 4 0]
mp-> [[0 1 2] [1 2 3] [2 3 4]]
Slice
S l i c e Slice Slice 是 G o Go Go中的一个重要的数据类型
S l i c e Slice Slice的类型仅仅由它所包含的元素的类型决定,和元素个数无关。
要创建一个长度不为 0 0 0的空 s l i c e slice slice,我们需要使用 make 函数
make
初始创建的时候我们可以直接开启它的长度然后去赋值
类似于开一个数组(?)
package main
import "fmt"
func main() {
s := make([]string, 3)
fmt.Println(s)
s[0] = "hah1"
s[1] = "ha2"
s[2] = "namomo"
//s[3] = "namo3"
fmt.Println(s)
}
//[ ]
//[hah1 ha2 namomo]
append
我们可以在一个 S l i c e Slice Slice的末尾中插入一个元素
package main
import "fmt"
func main() {
s := []string{}
s = append(s, "namo")
s = append(s, "namomo")
fmt.Println(s)
}
//[namo namomo]
copy
c o p y ( a , b ) copy(a,b) copy(a,b)将 b b b中的内容复制给 a a a
len
获取这个 s l i c e slice slice的长度是多少
func main() {
s := make([]string, 5)
fmt.Println(s)
s[0] = "hah1"
s[1] = "ha2"
s[2] = "namomo"
s[3] = "namomomo"
s[4] = "haha3"
fmt.Println(s)
c := make([]string, len(s))
copy(c, s)
fmt.Println("cpy:", c)
}
//[ ]
//[hah1 ha2 namomo namomomo haha3]
//cpy: [hah1 ha2 namomo namomomo haha3]
切片
类似于 P y t h o n Python Python中的切片,也是用 [ l : r ] [l:r] [l:r]来表示,是指截取一个从 l l l 到 r − 1 r - 1 r−1的 s l i c e slice slice内容
func main() {
s := make([]string, 5)
fmt.Println(s)
s[0] = "hah1"
s[1] = "ha2"
s[2] = "namomo"
s[3] = "namomomo"
s[4] = "haha3"
fmt.Println(s[2:4])
fmt.Println(s[:2])
fmt.Println(s[2:])
}
//[ ]
//[namomo namomomo]
//[hah1 ha2]
//[namomo namomomo haha3]
Map
M a p Map Map是 G o Go Go中内建的关联数据类型,我们可以类比称为 c p p cpp cpp 中的 m a p map map
要创建一个空 M a p Map Map,我们需要使用内建函数 m a k e make make:
m a k e ( m a p [ k e y − t y p e ] v a l − t y p e ) make(map[key-type]val-type) make(map[key−type]val−type)
然后我们使用典型的 n a m e [ k e y ] = v a l name[key] = val name[key]=val来设置键值对
定义一个字典
package main
import "fmt"
func main() {
mp := make(map[string]int)
mp["namo"] = 1
mp["namomo"] = 2
fmt.Println("mp->", mp)
//这也是一种直接定义的方式
//n := map[string]int{}
mp2 := map[string]int{"namo": 1, "aa": 2}
fmt.Println(mp2)
}
//mp-> map[namo:1 namomo:2]
//map[aa:2 namo:1]
遍历一个字典
我们可以直接采用 r a n g e range range函数来遍历
func main() {
mp := make(map[string]int)
mp["namo"] = 1
mp["namomo"] = 2
for i, v := range mp {
fmt.Println(i, v)
fmt.Printf("%s %d\n", i, mp[i])
}
}
//namo 1
//namo 1
//namomo 2
//namomo 2
删除字典中的一个键并且查找字典中是否存在某个键
package main
import "fmt"
func main() {
mp := make(map[string]int)
mp["namo"] = 1
mp["namomo"] = 2
fmt.Println("notdel", mp)
delete(mp, "namo")
fmt.Println("delete", mp)
//返回的数值是mp["namomo"],如果不存在在int中默认是0,res返回是否找到
_, res := mp["namomo"]
fmt.Println("res", res)
}
//notdel map[namo:1 namomo:2]
//delete map[namomo:2]
//res true
range函数
在上面 m a p map map和数组以及 s l i c e slice slice中都用到过,用法类似 p y py py的
结构体
G o Go Go的结构体是带类型的字段集合。
我们可以使用 t y p e n a m e s t r u c t type \ name \ struct type name struct { } \{\} {}来定义一个结构体,其中 n a m e name name是这个结构体的名字
结构体定义
定义的时候如果没有给值就会赋值那个类型的初始值
type person struct {
name string
age int
}
func main() {
fmt.Println(person{"namomo", 1})
fmt.Println(person{name: "namo2", age: 10})
fmt.Println(person{name: "ha"})
}
//{namomo 1}
//{namo2 10}
//{ha 0}
结构体指针
我们可以使用&
前缀来生成一个结构体指针,使用.
来访问结构体字段
结构体也是可变的
type person struct {
name string
age int
}
func main() {
s := person{name: "namo", age: 15}
s.name = "namomo"
fmt.Println(s)
sp := &s
sp.age = 100
fmt.Println(s)
}
//{namomo 15}
//{namomo 100}
方法
G o Go Go支持为结构体类型定义方法
定义方法的形式为 $func \ (username \ typename) funcname() val {} $
package main
import "fmt"
type rect struct {
width, height int
}
func (r *rect) area() int {
return r.width * r.height
}
func (r rect) perim() int {
return 2*r.width + 2*r.height
}
func main() {
ret := rect{10, 5}
fmt.Println(ret.area())
fmt.Println(ret.perim())
}
//50
//30
接口
要在 G o Go Go中实现一个接口,我们只需要实现接口中所有的方法。这里我们为 r e c t rect rect实现了 g e o m e t r y geometry geometry接口
结构体类型 $circle $和 r e c t rect rect都实现了 g e o m e t r y geometry geometry 接口, 所以我们可以将其实例作为 m e a s u r e measure measure 的参数。
package main
import (
"fmt"
"math"
)
type geometry interface {
area() float64
perim() float64
}
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (r circle) area() float64 {
return math.Pi * r.radius * r.radius
}
func (r circle) perim() float64 {
return 2 * math.Pi * r.radius
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{3, 4}
c := circle{5}
measure(r)
measure(c)
}
{3 4}
12
14
{5}
78.53981633974483
31.41592653589793
嵌入
s t r u c t struct struct里面套一个 s t r u c t struct struct
package main
import "fmt"
type base struct {
num int
}
func (b base) describe() {
fmt.Println("base with num = %d\n", b.num)
}
type container struct {
base
str string
}
func main() {
co := container{
base: base{
num: 1,
},
str: "some name",
}
fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)
}
(username \ typename) funcname() val {} $
package main
import "fmt"
type rect struct {
width, height int
}
func (r *rect) area() int {
return r.width * r.height
}
func (r rect) perim() int {
return 2*r.width + 2*r.height
}
func main() {
ret := rect{10, 5}
fmt.Println(ret.area())
fmt.Println(ret.perim())
}
//50
//30
接口
要在 G o Go Go中实现一个接口,我们只需要实现接口中所有的方法。这里我们为 r e c t rect rect实现了 g e o m e t r y geometry geometry接口
结构体类型 $circle $和 r e c t rect rect都实现了 g e o m e t r y geometry geometry 接口, 所以我们可以将其实例作为 m e a s u r e measure measure 的参数。
package main
import (
"fmt"
"math"
)
type geometry interface {
area() float64
perim() float64
}
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (r circle) area() float64 {
return math.Pi * r.radius * r.radius
}
func (r circle) perim() float64 {
return 2 * math.Pi * r.radius
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{3, 4}
c := circle{5}
measure(r)
measure(c)
}
{3 4}
12
14
{5}
78.53981633974483
31.41592653589793
嵌入
s t r u c t struct struct里面套一个 s t r u c t struct struct
package main
import "fmt"
type base struct {
num int
}
func (b base) describe() {
fmt.Println("base with num = %d\n", b.num)
}
type container struct {
base
str string
}
func main() {
co := container{
base: base{
num: 1,
},
str: "some name",
}
fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)
}