在需要编写go的目录(假设是go_code),在go_code下
go mod init go_code(目录名)
会在go_code目录下生成一个go.mod的初始化文件,在go_code目录下再创建一个目录.在该目录里编写代码
二进制 BIN 0 , 1, 10
八进制 OCT 0,1,2,3,4,5,6,7,10(一零,不是十)
十进制 DEC
十六进制 HEX 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10
位:(内存地址的宽度)
BYTE: 8位 一个字节
WORD: 16位
DWORD: 32位
QWORD: 64位
package main //引入包
import fmt //引入fmt的库,在go中导入了什么库,就必须使用,否则报错
func main(){
fmt.Println("hello world") //不需要分号
}
package main
import fmt
func main(){
var num int = 5 //var跟php类似的意思,赋值号必须有空格
fmt.Println(num) //创建了num的变量就必须使用,否则报错
}
//初始化
var a int = 5
//默认值(0)
var b int
//自动化推导(auto)
c := 10
//多变量定义
var d,e int
d = 20
e = 30
//多变量定义
var(
f int = 2
g int = 3
)
//在定义过变量之后i,要改变值直接改就可以
a = 6 //a原本是5
基本类型 | 复合类型 |
---|---|
int | array |
folat | slice |
string | map |
bool | struct |
pointer | |
function | |
chan |
按照特性来分
值类型 | 引用类型(传递地址,多变量指向同一内存地址) |
---|---|
int | slice |
float | |
string | |
bool | |
struct | |
深拷贝是把数据都复制一份在传递,被传递的跟原有数据已经没关系了
浅拷贝是传址,一个改变另一个也改变
有符号整型 | 无符号整型 | 字符(ASCII) | 字符(unicode) |
---|---|---|---|
int (默认64bit) | uint | byte | rune |
int8 (8bit) | uint8 | ||
int16 (16bit) | uint16 | ||
int32 (32bit) | uint32 | ||
int64 (64bit) | uint64 |
符号位是从左往右数第一位(有符号整型),0是正数,1是负数,所以int8是-128到127
如果求的数是负数,那么则要求该数对应的补码,即把所有数取反(0换1,1换0)那么本来最大的127(0111 1111)就变成了(1000 0000)的-128
int16是-32768到32767,uint16是0到65535
ASCII可以等于成uint8
在go中的unicode版本是UTF-32,4字节,32bit
float32 4字节
float64 8字节
var numa int64 = 12138
var numb int8 = int8(numa)
fmt.Println(numb) //106
var numa int64 = 12138
var numb int8 = int8(numa)
var numc int32 =int32(numb)
var str string = fmt.Sprintf("%d %d %d",numa,numb,numc)
//fmt.Sprintf是吧其它类型的值转化成字符串的专用函数
//输出12138 106 106
package main
import "fmt"
const (
numA = 11
numB = 22
)
const (
a = 1 //在前一个常量定义后,如果后一个常量未被定义,则跟前一个常量相等
b
c = 33
d
)
const (
numC = iota //自带的枚举量,会从0开始计数
numD
numE
numF
)
func main() {
const pi = 3.1415 //既可以定义在main函数内也可以在外部定义
//3.1415
fmt.Println(pi)
//11 22
fmt.Println(numA, numB)
//1 1 33 33
fmt.Println(a, b, c, d)
//0 1 2 3
fmt.Println(numC, numD, numE, numF)
}
fmt.Println((1>2)) //输出false
&& //左右两侧均为真则结果为真
|| //或
! //非
var h int = 189 //128+32+16+8+4+1 1011 1101
var i int = 245 //128+64+32+16+4+1 1111 0101
var m int = h & i
fmt.Println(m) //181 1011 0101
位一样的变为1,不一样的为0
### 或运算(按位或)
都是0为0,其余为1
```|```
### 异或运算
两位一样则为0,不一样则为1
```^```
## 运算符
### 左移运算符 <<
高位抛弃,低位补零
```go
var h int = 189 //1011 1101
var j int = h << 3 //1011110 1000 -> 1110 1000
fmt.Println(j) //232
符号位是什么就补什么
int默认是64位,正数的符号位是0,则右移之后原来的位置补0
var flag int
fmt.Scanf("%d", &flag)
if flag == 10 { //go的if中没有()
fmt.Println("yes")
} else if flag >= 11 && flag <= 20 {
fmt.Println(15)
} else {
fmt.Println(21)
}
switch flag {
case 1: //如果flag是1
fmt.Println(1)
case 2:
fmt.Println(2)
case 3, 4: //如果flag是3或4
fmt.Println("3 | 4")
default:
fmt.Println("大于4") //else
}
for i:=1; i<=10; i+=4{
fmt.Println(i)
}
for x := 1; x <= 9; x++ {
for y := 1; y <= x; y++ {
fmt.Printf("%d*%d=%d", y, y, y * y)
}
fmt.Println()
}
//这种主要用于循环数组和字符串等
var str string = "abcdefg"
for index, value := range str {
fmt.Printf("%d %c", index, value)
fmt.Println()
}
//index和value不是默认的,只是两个接收内容的变量,也可以用占位符_替代,名字是什么都可以,比如inde和valu
//for _,_ := range 变量名{}
//如果只想获得index,后面的可以不写,占位符也不用写,但如果指向获得后面的,则前面的必须写占位符
//continue
for i:= 1;i<=10;i++{
if i==5{
continue
}
fmt.Println(i)
}
//结果是1 2 3 4 6 7 8 9 10
//break
for i:= 1;i<=10;i++{
if i==5{
break
}
fmt.Println(i)
}
//结果是1 2 3 4
//如果是嵌套循环,则
for x := 1; x <= 2; x++ {
for i := 1; i <= 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
}
//结果是1 2 3 4 1 2 3 4,只跳出一层循环
var num * int = nil //初始化一个空指针,nil就是null的意思
var numa int = 123
num = &numa
fmt.Println(num) //输出0xc0000a6058
fmt.Pritln(*num) //输出123
*num = 234
fmt.Println(*num, numa) //输出234 234
//空指针
var n *int = nil
fmt.Println(n, *n)
*n = 500
fmt.Println(n, *n)
//会报错
/*panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x9adf7c]
goroutine 1 [running]:
main.main()
d:/桌面/go/first/hello.go:15 +0x15c
exit status 2*/
//报错原因是本来n是空指针,所以没有占用内存空间,不能进行直接赋值
var n *int = nil
n = new(int)
fmt.Println(n, *n)
*n = 500
fmt.Println(n, *n)
//输出
//0xc0000160d8 0
//0xc0000160d8 500
var arr = [4]string{"apple", "orange", "pear", "banana"}
arr[3] = "123"
fmt.Println(arr[3])
//结果是123
//可以直接打印
fmt.Println(arr)
//打印数组
for index, value := range arr {
fmt.Println(value, index)
}
/*
apple 0
orange 1
pear 2
123 3
*/
//多维数组
var arr = [3][2]string{
{"11", "12"}, //用逗号分隔
{"21", "22"},
{"31", "32"}} //最后一个括号一定要在同一行否则会报错
fmt.Println(arr[2][1])
//打印多维数组
for _, value := range arr { //这里的每个value都是一个一维数组
for _, va := range value {
fmt.Println(va) //这里的va是一个值
}
}
可以理解成可变长度的数组
s1 := []int{1,2,3,4} //数组不写len,默认为切片
s1 := make([]int,2,4) //make(slice(slice就是[])/map/chan,初始时有多少个元素(len),最大有多少个元素(cap))
//甚至可以建立一个内部元素是map的切片 s1:=make([]map[string]string,2,6)
fmt.Println(s1) //结果是[0 0 0 0]
s1[1] = 5 //直接修改只能在初始范围内修改,想增加需要额外函数
fmt.Println(s1) //[0,5]
//append函数可以对切片进行增加/扩容操作
s1 = append(s1, 2, 3)
fmt.Println(s1) //[0 5 2 3]
s1 = append(s1, 55)
fmt.Println(s1) //本来s1最大容纳元素是5,但append函数可以自动扩容(cap翻倍),在上一步直接append(s1,2,3,55)也可以,后面新添加的元素数量没有限制
s2 := make([]int, 1, 2)
s1 = append(s1, s2...) //也可以在一个切片后直接添加一个切片,但后面的切片必须带上...
fmt.Println(s1) //[0 5 2 3 55 0]
fmt.Printf("%d %d", len(s1), cap(s1)) //6 8
var arr = [4]int{1, 2, 3, 4}
fmt.Println(arr)
s1 := arr[:2]
fmt.Printf("%d %d", cap(s1), s1) //4 [1 2] cap默认是原数组长度
s2 := arr[:] //必须加[:],否则s2将是数组而不是切片
fmt.Println(s2) //默认是全取 [1 2 3 4]
s3 := arr[2:4] //左闭右开实际是第2和3个元素(0 1 2 3的顺序)
fmt.Println(s3) //[3 4]
//对数组的直接引用,会使切片指向数组,数组改变,切片也会改变,但当切片扩容之后,会自动指向新的数组,原数组改变,切片不再改变
//切片引用数组,本质是获取了数组的指针,所以切片改变,数组也会改变
s1 := []int{1, 2, 3, 4}
fmt.Println(s1)
s2 := []int{7, 8}
//情况1
copy(s1, s2) //s1是被赋值的(待操作),s2是进行赋值的
fmt.Println(s1, s2) //[7 8 3 4] [3 4]
//情况2
copy(s2,s1) //s1长度大于s2时,s2会被全部修改,但不会被扩容
fmt.Println(s2) //[1 2]
//情况3
//可以手动选择从哪里开始赋值
copy(s1, s2[:1])
fmt.Println(s1) //[7 2 3 4]
//情况4
copy(s1[2:], s2[:1])
fmt.Println(s1) //[1 2 7 4]
就是键值对
使用map过程中需要注意的几点:
//直接创建,当不赋值时为nil,不能直接更改
var map1 map[int]string //map是类型,int是键名的变量类型,string是键值的变量类型
//用make创建,即使没赋值也不是nil,可以直接使用
map2 := make(map[int]string) //只有map可以这样,slice必须加len和cap,chan可以加cap也可以不加cap
//直接创建并赋值
map1 := map[string]int{"html": 60, "css": 70, "js": 80} //中间用逗号分隔,赋值用冒号
//可以直接进行增加/修改键值对
map1 := map[string]int{"html": 60, "css": 70, "js": 80}
fmt.Println(map1) //map[css:70 html:60 js:80]
map1["py"] = 50
fmt.Println(map1) //map[css:70 html:60 js:80 py:50]
//删除需要用到delete函数
delete(map1,"py") //如果键名是int就不用加引号,这里是因为是字符串才加的引号
fmt.Println(map1) //map[css:70 html:60 js:80]
//int:string型
map1 := map[int]string{1: "太极", 2: "两仪", 3: "四象", 4: "八卦"}
keys := make([]int, 0, len(map1))
fmt.Println(keys)
for index := range map1 {
keys = append(keys, index)
}
fmt.Println(keys)
sort.Ints(keys)
for _, k := range keys {
fmt.Println(k, map1[k])
}
//string:int型
map1 := map[string]int{"html": 60, "css": 70, "js": 80}
for k, v := range map1 {
fmt.Println(k, v)
}
在一个函数中,如果有内层函数,则在外层函数定义的局部变量可以被内层函数不经调用直接使用,并且如果变量被内层函数使用后,在外层函数也结束后,该局部变量不会被释放(类似c的const)
本质是指针,指向数组的地址
var arr := [4]int{1,2,3,4}
var p *[4]int
p=&arr //p有自己的地址,但是p指向数组的地址
本质是数组,存储的内容是指针
a:=1
b:=2
c:=3
d:=4
arr1:=[4]int{a,b,c,d}
arr2:=[4]*int{&a,&b,&c,&d}
arr1[0] = 5
fmt.Println(a) //1
*arr2[0] = 5
fmt.Println(a) //5
//数组的直接赋值时深拷贝,如果时指针数组则是浅拷贝
*[4] type 先指针再数组,所以是数组指针
[4]* type 先数组再指针,所以是指针数组
结构体内部是结构体的属性,而在外部创建对象,并给对象的属性赋值
func main() {
var p1 person //创建一个对象
p1.age = 18
p1.name = "小明"
p1.sex = "m"
fmt.Println(p1)
//第二种定义方法
p2 := person{}
p2.age = 19
fmt.Println(p2.age)
//第三种定义方法
p3 := person{age: 20, sex: "f"} //结构体的赋值是冒号,跟map一样
fmt.Println(p3)
}
type person struct { //type和struct是关键字
age int
name string
sex string
}
func main() {
var p1 person
p1.age = 18
p1.name = "小明"
p1.sex = "m"
var p *person = &p1
fmt.Println(p, *p) //&{18 小明 m} {18 小明 m} 第一个输出带&
p.age = 29 //指针修改,则原来的也修改
fmt.Println(p1) //{29 小明 m}
}
type person struct {
age int
name string
sex string
}
func main() {
w1 := worker{name: "小明", age: 19, sex: "m"}
w1.work() //小明 在工作
w2 := &worker{name: "小明", age: 19, sex: "m"} //&是取地址,这里是w2是结构体指针
w2.work() //小明 在工作
}
type worker struct {
name string
age int
sex string
}
func (w worker) work() { //这里建立一个局部的结构体变量的对象用于进行操作 这里是空格不是逗号,work()是方法名
fmt.Println(w.name, "在工作")
}
package main
import "fmt"
func main() {
//创建pers父类对象
p1 := pers{name: "小明", age: 18}
fmt.Println(p1.name, p1.age)
p1.eat()
//创建子类对象
s1 := stu{pers{name: "小光", age: 19}, "qdyz"} // pers的结构体嵌套是匿名字段,所以后面的school也只能用匿名字段的方法赋值
fmt.Println(s1.school)
//子类对象调用父类方法
s1.eat()
//子类调用自定义方法,父类对象不能调用子类的方法
s1.study()
}
//父类
type pers struct {
name string
age int
}
//子类
type stu struct {
pers //结构体嵌套,模拟继承性
school string
}
//父类方法
func (p pers) eat() {
fmt.Println("父类方法,吃米饭")
}
//子类自定义方法
func (s stu) study() {
fmt.Println("子类自定义方法,在学习")
}
//子类重写方法
func (s stu) eat() { //方法中的局部变量的名字可以一样
fmt.Println("子类重写的吃饭方法")
}
接口有点类似结构体的感觉,只要有别的结构体的对象调用接口,那么这些结构体都可以相当于包含在接口所在的大类里
接口可以创建接口类型的变量,而且调用了接口的结构体的对象可以算作接口创建的对象
但是接口创建的变量不能使用调用接口的结构体中的对象的信息
接口中的内容是方法,不是具体值
package main
import "fmt"
func main() {
m1 := mouse{"原厂"}
m1.start()
m1.end()
u1 := uDisck{"64g"}
u1.start()
u1.end()
test(m1)
test(u1)
var usb USB = m1
usb.start()
arr := [3]USB{m1, u1}
fmt.Println(arr)
}
//定义接口 usb
type USB interface {
start()
end()
}
//定义鼠标类对象
type mouse struct {
name string
}
//定义u盘类对象
type uDisck struct {
name string
}
//鼠标类对象的接口
func (m mouse) start() {
fmt.Println(m.name, "鼠标开始")
}
func (m mouse) end() {
fmt.Println(m.name, "鼠标结束")
}
//u盘类对象的接口
func (u uDisck) start() {
fmt.Println(u.name, "u盘ok")
}
func (u uDisck) end() {
fmt.Println(u.name, "可以拔出")
}
func test(usb USB) {
usb.start()
usb.end()
}
package main
import "fmt"
func main() {
map1 := make(map[int]interface{})
map1[0] = "hahah"
map1[1] = 123
fmt.Println(map1)
}
package main
import (
"fmt"
"math"
)
func main() {
s1 := sanj{3, 4, 5}
fmt.Println(s1.area())
fmt.Println(s1.peri())
c1 := cir{2}
fmt.Println(c1.peri())
fmt.Println(c1.area())
var sh1 shape = s1
sh1.area()
test(s1)
test(c1)
test(sh1)
fmt.Print("\n")
fmt.Println("接口断言")
gettype(s1)
gettype(c1)
gettype(sh1)
fmt.Println("另一种接口断言")
gete(s1)
gete(c1)
gete(sh1)
}
func gettype(a shape) {
//接口断言,判断传入的数据属于哪个结构体
//判断是否属于三角类型
if v, ok := a.(sanj); ok {
fmt.Println("三角形,三边分别是", v.a, v.b, v.c)
} else if va, ok := a.(cir); ok {
fmt.Println("是圆形,半径是", va.r)
} else {
fmt.Println("no")
}
}
func gete(a shape) {
switch v := a.(type) { //type是关键字,括号里面就直接写type
case sanj:
fmt.Println("是三角,第一个边长是", v.a)
case cir:
fmt.Println("是圆,半径是", v.r)
}
}
type shape interface {
peri() float64
area() float64
}
type sanj struct {
a, b, c float64
}
func (s sanj) peri() float64 {
return s.a + s.b + s.c
}
func (s sanj) area() float64 {
p := s.peri() / 2
are := math.Sqrt(p * (p - s.a) * (p - s.b) * (p - s.c))
return are
}
type cir struct {
r float64
}
func (c cir) peri() float64 {
return 3 * c.r * 2
}
func (c cir) area() float64 {
return 3 * c.r * c.r
}
func test(s shape) {
fmt.Printf("面积是:%.2f,周长是%.2f", s.area(), s.peri())
}
处理异常需要调用os包(import os)
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("test.txt")
if err != nil {
fmt.Println("不存在文件")
return
}
fmt.Println("成功读取文件", f.Name())
}
//只打印不存在文件
//sort排序(正序) 只能用于切片,不能用于数组
arr := [4]int{5, 3, 1, 6}
arr1 := arr[:]
sort.Ints(arr1)
fmt.Println(arr1) //1 3 5 6
//字符串按照首字母ascii排序
ar := []string{"abx", "A", "UK", "呃呃呃"}
sort.Strings(ar)
fmt.Println(ar) //[A UK abx 呃呃呃]
package main
import "fmt"
func main() {
var ge int
var sh int
var bai int
for i := 100; i < 1000; i++ {
ge = i % 10
sh = i / 10 % 10
bai = i / 100
if i == ge*ge*ge+sh*sh*sh+bai*bai*bai {
fmt.Println(i)
}
}
}
j要从2开始
package main
import "fmt"
func main() {
for i := 2; i <= 100; i++ {
flag := true
for j := 2; j < i; j++ {
if i%j == 0 {
flag = false
break
}
}
if flag {
fmt.Println(i)
}
}
}