赞
踩
目录
配置:
一文轻松实现在VSCode中编写Go代码_vscode 开发go-CSDN博客
- package main
-
- //导入包
- import "fmt"
-
- //主函数,入口函数
- func main() { //大括号必须和函数在同一行
- //打印输出
- fmt.Println("hello go")
- }
导入多个包:
- import "fmt"
- import "time"
or
- import(
- "fmt"
- "time"
- )
四种定义方式
- func main() {
- var a int
- fmt.Print(a) //默认为0
-
- var b int = 3
- fmt.Print(b) //3
-
- var c = 10
- fmt.Print(c) //10
- fmt.Printf("c is %T", c) //c is int
-
- d := 3.45
- fmt.Printf("d = %f", d) //d=3.450000
- }
第四种方法只能使用于局部变量,例如下面这张方法是不可以的:
- a :=200
- //non-declaration statement outside function body
- func main() {
- fmt.print(a)
- }
声明多个变量
- func main() {
- var a, b = 3, "asdad"
- fmt.Print(a, b)
-
- var c, d int = 3, 4
- fmt.Print(c, d)
-
- var (
- e int = 4
- f = "aeasd"
- )
- fmt.Print(e, f)
-
- g, h := 9, false
- fmt.Println(g, h)
- }
数据类型转换
一、强制类型转换
但是只有相同底层类型的变量之间可以进行相互转换(如将 int16 和 int32 相互转换,float 类型和 int 类型相互转换),不同底层类型的变量相互转换时会引发编译错误(如 bool 类型和 int 类型,string 与 int 类型之间的转换):
二、 strconv包:字符串和数值类型的相互转换
1. Itoa():整型转字符串 integer to alphanumeric
2. Atoi():字符串转整型 alphanumeric to integer
3. Parse 系列函数(str转其他): ParseBool()、ParseInt()、ParseUint()、ParseFloat()
4.Format 系列函数(其他转str): FormatBool()、FormatInt()、FormatUint()、FormatFloat()
5.Append 系列函数(其他转str后加到切片中): AppendBool()、AppendFloat()、AppendInt()、AppendUint()
golang的数据类型
golang 的数据类型_golang数据类型-CSDN博客
常量不允许重复赋值
- func main() {
- const PI float32 = 3.14
- fmt.Printf("PI: %v\n", PI)
- const a = 90
- fmt.Printf("a: %v\n", a)
- a = 99 //cannot assign to a (neither addressable nor a map index expression)
- }
常量可以枚举
- const (
- Unknown = 0
- Female = 1
- Male = 2
- )
可以使用iota实现自增赋值,例如下面这种一个一个赋值很繁琐
- const (
- CategoryBooks = 0
- CategoryHealth = 1
- CategoryClothing = 2
- )
于是:
- const (
- CategoryBooks = iota // 0
- CategoryHealth // 1
- CategoryClothing // 2
- )
在每个枚举中,iota从0开始,每行递增
也可以在第一行使用公式,下面所有行都会使用同样的公式
- const (
- CategoryBooks = 10 * iota //0
- CategoryHealth //10
- CategoryClothing //20
- )
公式在中途也可以变化,iota的值不会中断
- const (
- CategoryBooks = 10 * iota //0
- CategoryHealth //10
- CategoryClothing //20
-
- a = 100 * iota //300
- b //400
- c //500
- )
注意,iota只能在const中使用
- // 普通函数
- func foo1(x int, y int) int {
- return x + y
- }
-
- func foo2() {
- fmt.Printf("\"hello\": %v\n", "hello")
- }
-
- // 多返回值函数
- func foo3(x, y int) (int, string) {
- return 9, "asdad"
- }
-
- // 给返回值命名
- func foo4() (r1 int, r2 string) {
- fmt.Printf("r1: %v\n", r1) //0
- fmt.Printf("r2: %v\n", r2) //""
- //说明已经命名的返回值就是一个局部变量,具有默认值
-
- r1 = 9
- r2 = "qwqw"
- return
- }
-
- func main() {
- a := foo1(1, 2)
- fmt.Printf("a: %v\n", a)
-
- foo2()
-
- c, d := foo3(1, 2)
- fmt.Printf("c: %v\n", c)
- fmt.Printf("d: %v\n", d)
-
- e, f := foo4()
- fmt.Printf("e: %v\n", e)
- fmt.Printf("f: %v\n", f)
- }
lib1:
- package lib1
- import (
- "fmt"
- "lib2"
- )
- func init() {
- fmt.Println("lib1 init")
- lib2.Lib2_test()
- }
- func Lib1_test() {
- fmt.Println("lib1_test")
- }
lib2:
- package lib2
- import "fmt"
- func init() {
- fmt.Println("lib2 init")
- }
- func Lib2_test() {
- fmt.Println("lib2_test")
- }
main:
- package main
- import (
- "fmt"
- "lib1"
- )
- func main() {
- fmt.Print("main")
- lib1.Lib1_test()
- // lib2 init
- // lib1 init
- // lib2_test
- // mainlib1_test
- }
值得注意的是,包中的函数必须是大写字母开头的,这样这个函数才能在包外被调用,可以看成是java中public的一种形式
在golang中,如果导入了包,却不调用包的方法,会报错
但是如果我只想执行包的init函数却不使用包中的方法,可以使用匿名包,这样不能调用包的方法,但是会执行init
- import (
- "fmt"
- _ "lib1"
- )
- func main() {
- fmt.Print("main")
- }
可以给包起别名
- import (
- "fmt"
- mylib1 "lib1"
- )
- func main() {
- fmt.Print("main")
- mylib1.Lib1_test()
-
- }
跟c语言一样
- package main
-
- //导入包
- import "fmt"
-
- func changevalue(p *int) { //申明 p 为指针型变量,指向一个int型的变量,p本身存储的是这个int变量的地址
- *p = *p * 10 //*p 表示指向的这个变量本身
- }
-
- func main() {
- a := 10
- changevalue(&a) //&a表示a的地址
- fmt.Printf("a: %v\n", a) //100
- }
- package main
-
- //导入包
- import "fmt"
-
- func changevalue(a *int, b *int) {
- temp := *a
- *a = *b
- *b = temp
- }
-
- func main() { //大括号必须和函数在同一行
- a := 10
- b := 20
- changevalue(&a, &b)
- fmt.Printf("a: %v\n", a) //20
- fmt.Printf("b: %v\n", b) //10
- }
二级指针,指向指针的指针
- package main
-
- //导入包
- import (
- "fmt"
- )
-
- // 普通函数
-
- func main() {
- a := 10
- var p *int = &a
- var p1 **int = &p
-
- fmt.Println(&p) //0xc000070030
- fmt.Println(p1) //0xc000070030
-
- }
在当前函数体的最后运行
- func main() {
- defer fmt.Println("main end")
- fmt.Printf("\"alalal\": %v\n", "alalal")
- // "alalal": alalal
- // main end
- }
如果存在多个defer,则遵循 栈 的原则
- func main() {
- defer fmt.Println("main end1")
- defer fmt.Println("main end2")
- fmt.Printf("\"alalal\": %v\n", "alalal")
- // "alalal": alalal
- // main end2
- // main end1
- }
在函数调用中,defer在return之后,这个很好理解,因为defer应该在函数体最后执行,最先入栈,在return之后
- func returnfunc() int {
- fmt.Println("return end")
- return 0
- }
-
- func testfunc() int {
- defer fmt.Println("func end")
- return returnfunc()
- }
- func main() {
- testfunc()
- // return end
- // func end
- }
- func main() {
- var myarray [10]int
- myarray2 := [10]int{1, 2, 3, 4}
- }
固定长度数组需要指定数组长度,且有默认值
当固定长度数组作为形参时,进行的是值传递,而不是引用传递
- func change_array(myarry [4]int) {
- myarry[0] = 100
- }
- func main() {
- myarray2 := [4]int{1, 2, 3, 4}
-
- change_array(myarray2)
- //myarray2的值不改变
- }
而且当函数形参是固定长度数组时,传入其他长度的数组也不可以,非常的不方便
- func main() {
- var myarray [10]int
- myarray2 := [10]int{1, 2, 3, 4}
- for i := 0; i < len(myarray); i++ {
- fmt.Printf("myarray[i]: %v\n", myarray[i])
- }
- for index, value := range myarray2 {
- fmt.Printf("index:%d,value:%d\n", index, value)
- }
- }
也可以只遍历下标:
- myarray2 := [10]int{1, 2, 3, 4}
- for index := range myarray2 {
- fmt.Printf("index:%d\n", index)
- }
也叫 切片
- func change_array(myarry []int) {
- myarry[0] = 100
- }
- func main() {
- myarray2 := []int{1, 2, 3, 4}
- fmt.Printf("%T \n", myarray2) //[]int
- change_array(myarray2)
- for index, value := range myarray2 {
- fmt.Printf("index:%d,value:%d\n", index, value)
- } //myarray2的值改变
- }
多种声明方式
- func main() {
- slice1 := []int{}
- slice1 = make([]int, 3) //开辟三个空间
- fmt.Printf("len(slice): %d, slice1: %v\n", len(slice1), slice1)
- // len(slice): 3, slice1: [0 0 0]
-
- slice2 := make([]int, 4)
- fmt.Printf("len(slice): %d, slice2: %v\n", len(slice2), slice2)
- // len(slice): 4, slice2: [0 0 0 0]
-
- }
追加元素:
- func main() {
- slice1 := []int{}
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 0, cap: 0, slice1: []
- slice1 = append(slice1, 2)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 1, cap: 1, slice1: [2]
- }
这里需要说一下 len 和cap
- func main() {
- slice1 := make([]int, 3)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 3, cap: 3, slice1: [0 0 0]
- slice1 = append(slice1, 2)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 4, cap: 6, slice1: [0 0 0 2]
- }
当我们为其开辟是空间3时,其默认的cap也是3,cap是系统为数组一次性开辟空间的大小
当我再次加入元素时,长度变为了4,但是cap变成了6,也就是说在加入时自动增加了三个大小的空间
当然我们也可以指定cap
- func main() {
- slice1 := make([]int, 3, 5)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 3, cap: 3, slice1: [0 0 0]
- slice1 = append(slice1, 2)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 4, cap: 6, slice1: [0 0 0 2]
- slice1 = append(slice1, 2)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 5, cap: 5, slice1: [0 0 0 2 2]
- slice1 = append(slice1, 2)
- fmt.Printf("len(slice): %d, cap: %d, slice1: %v\n", len(slice1), cap(slice1), slice1)
- // len(slice): 5, cap: 5, slice1: [0 0 0 2 2]
-
- }
当然只有在增加元素超过了len时,才会使用cap增加空间
截取方法和python一样,值得注意的是,这里的截取都是浅拷贝
- func main() {
- s := []int{1, 2, 3}
- s1 := s[0:2]
-
- s1[0] = 100
- fmt.Printf("s1: %v\n", s1)
- fmt.Printf("s: %v\n", s)
- // s1: [100 2]
- // s: [100 2 3]
-
- }
如果想实现深拷贝:
- func main() {
- s := []int{1, 2, 3}
- s1 := make([]int, 2)
-
- copy(s1, s)
-
- s1[0] = 100
- fmt.Printf("s1: %v\n", s1)
- fmt.Printf("s: %v\n", s)
- // s1: [100 2]
- // s: [1 2 3]
-
- }
- slice := make([]int, 2, 4)
- append_slice := []int{1, 2}
- fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
-
- slice = append(slice, append_slice...)
- fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
-
- slice = append(slice, 10, 20)
- fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
-
- slice = append(slice, 30, 40, 50)
- fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
-
- //output
- slice addr:0xc0420540a0 len:2 cap:4 slice:[0 0]
- slice addr:0xc0420540a0 len:4 cap:4 slice:[0 0 1 2]
- slice addr:0xc04207a080 len:6 cap:8 slice:[0 0 1 2 10 20]
- slice addr:0xc04208a000 len:9 cap:16 slice:[0 0 1 2 10 20 30 40 50]
删除等操作可以查看:
初识go语言之 数组与切片(创建,遍历,删除,插入,复制)_golang创建数组-CSDN博客
声明方式1:
- var mymap map[int]string
- if mymap == nil {
- fmt.Print("mymap is empty\n")
- }
- // mymap is empty
这种情况下给map增加键值对是非法的,因为此时mymap的容量为0
但是如果是下面这种是可以的,因为默认分配了空间:
- var mymap1 = map[int]string{}
- mymap1[0] = "awew"
声明方式2:
可以使用make申请空间,且这个空间是动态可以扩展的
- mymap2 := make(map[int]string, 1)
- mymap2[1] = "aa"
- mymap2[2] = "aa"
- fmt.Printf("mymap2: %v\n", mymap2)
声明方式3:
不主动申请空间,但是其默认是有空间的
- mymap3 := make(map[int]string)
- mymap3[2] = "sad"
- fmt.Printf("mymap3: %v\n", mymap3)
声明方式4:
- mymap4 := map[int]string{
- 1: "aa",
- 2: "bb",
- 3: "cc",
- }
- mymap4[4] = "ee"
- fmt.Printf("mymap4: %v\n", mymap4)
- mymap4 := map[int]string{
- 1: "aa",
- 2: "bb",
- 3: "cc",
- }
- mymap4[4] = "ee"
- for key, value := range mymap4 {
- fmt.Printf("key: %v\n", key)
- fmt.Printf("value: %v\n", value)
- }
- // key: 1
- // value: aa
- // key: 2
- // value: bb
- // key: 3
- // value: cc
- // key: 4
- // value: ee
-
- mymap4 := map[int]string{
- 1: "aa",
- 2: "bb",
- 3: "cc",
- }
- mymap4[4] = "ee"
- fmt.Printf("mymap4: %v\n", mymap4)
- delete(mymap4, 4)
- fmt.Printf("mymap4: %v\n", mymap4)
- // mymap4: map[1:aa 2:bb 3:cc 4:ee]
- // mymap4: map[1:aa 2:bb 3:cc]
- func main() {
- m := make(map[string]int)
- m["张三"] = 10
- m["李四"] = 20
- value, ok := m["张四"]
-
- if ok {
- fmt.Println(value)
- } else {
- fmt.Println("查无此人")
- }
- }
当map作为形参时,也是引用传递
Golang底层原理剖析之map_golang map底层-CSDN博客
这里的结构体可以看出是 类
- type Book struct {
- name string
- price int
- }
-
- func main() {
- var mathbook Book
- mathbook.name = "lalal"
- mathbook.price = 12
- fmt.Printf("mathbook: %v\n", mathbook)
- // mathbook: {lalal 12}
-
- }
- type Book struct {
- name string
- price int
- }
-
- func changebook(book Book) {
- book.price = 100
- }
-
- func changebook2(book *Book) {
- book.price = 100
- }
-
- func main() {
- var mathbook Book
- mathbook.name = "lalal"
- mathbook.price = 12
- changebook(mathbook)
- fmt.Printf("mathbook: %v\n", mathbook)
- // mathbook: {lalal 12}
- changebook2(&mathbook)
- fmt.Printf("mathbook: %v\n", mathbook)
- // mathbook: {lalal 100}
-
- }
这说明作为形参传递是 值传递,而不是引用传递
结构体方法的定义:
- type Book struct {
- name string
- price int
- }
-
- func (this Book) show() {
- fmt.Printf("this.name: %v\n", this.name)
- fmt.Printf("this.price: %v\n", this.price)
- }
-
- func (this Book) changeprice(new_price int) {
- this.price = new_price
- }
-
- func (this *Book) changeprice1(new_price int) {
- this.price = new_price
- }
-
- func main() {
- var mathbook Book
- mathbook.name = "lalal"
- mathbook.price = 12
- mathbook.show()
- // mathbook: {lalal 12}
-
- mathbook.changeprice(112)
- mathbook.show()
-
- mathbook.changeprice1(112)
- mathbook.show()
-
- // this.name: lalal
- // this.price: 12
- // this.name: lalal
- // this.price: 12
- // this.name: lalal
- // this.price: 112
-
- }
当调用
mathbook.changeprice()
时相当于changeprice(mathbook)
,实参和行参都是类型 Book,可以接受。此时在changeprice
()中的t只是参数t的值拷贝,所以method1
()的修改影响不到main中的t变量。当调用
mathbook.changeprice1()
=>changeprice1(mathbook)
,这是将 Book 类型传给了 *Book 类型,go可能会取mathbook
的地址传进去:changeprice1(&mathbook)
。所以changeprice1
() 的修改可以影响mathbook
。
由于结构体作为形参是指传递,所以在改变参数时务必使用 地址传参
在go中的struct中,类名、属性名、方法名大写表示对外可以访问,也就是java中的public
- type Person struct {
- name string
- sex string
- }
-
- func (this *Person) Eat() {
- fmt.Print("person eat")
- }
-
- type Super_man struct {
- Person //继承Person类
- level int
- }
-
- func (this *Super_man) Eat() { //重写父类方法
- fmt.Print("super_man eat")
- }
-
- func (this *Super_man) Fly() { //定义新的方法
- fmt.Print("super_man fly")
- }
-
- func main() {
- //两种声明对象的方式
- super_man1 := Super_man{Person{"lee", "male"}, 2}
-
- var super_man2 Super_man
- super_man2.name = "lee"
- super_man2.sex = "male"
- super_man2.level = 2
-
- super_man1.Fly()
- super_man2.Fly()
- }
- type Animal interface {
- Sleep()
- GetColor() string
- }
-
- type Cat struct {
- color string
- }
-
- func (this *Cat) Sleep() {
- fmt.Print("CAT IS SLEEPING\n")
- }
- func (this *Cat) GetColor() string {
- return this.color
- }
-
- type Dog struct {
- color string
- }
-
- func (this *Dog) Sleep() {
- fmt.Print("Dog IS SLEEPING\n")
- }
- func (this *Dog) GetColor() string {
- return this.color
- }
-
- func main() {
- var animal Animal
- animal = &Cat{"blue"}
- fmt.Printf("animal.GetColor(): %v\n", animal.GetColor())
- animal.Sleep()
- // animal.GetColor(): blue
- animal = &Dog{"black"}
- fmt.Printf("animal.GetColor(): %v\n", animal.GetColor())
- animal.Sleep()
- // animal.GetColor(): blue
- // CAT IS SLEEPING
- // animal.GetColor(): black
- // Dog IS SLEEPING
- }
上面这部分代码定义了一个接口 Animal,其中定义了2个方法
Cat和Dog类只需要完全实现这2个方法(也可以有接口中没有定义的方法), 就可以实现和Animal接口的多态,可以用鸭子类型理解
为了更加直观的实现多态:
- func animal_is_sleeping(animal Animal) {
- animal.Sleep()
- }
-
- func main() {
- mycat := Cat{"blue"}
- animal_is_sleeping(&mycat)
- // CAT IS SLEEPING
- }
在golang中,只能借助接口实现多态,使用父类是无法实现多态的,当然,如果B的父类是A,而A实现了接口C的方法,那么B也可以与C形成多态
interface接口可以跟所有的类形成多态:
- func myshow(arg interface{}) {
- fmt.Println(arg)
- }
-
- func main() {
- myshow(12)
- myshow("asdas")
- myshow([]int{1, 2, 3})
- myshow(map[int]int{1: 2, 2: 3})
- // 12
- // asdas
- // [1 2 3]
- // map[1:2 2:3]
- }
可以判断接口现在对应的类是哪个:
- var myanimal Animal
- myanimal = &Cat{"blue"}
-
- value, ok := myanimal.(*Cat)
- fmt.Printf("ok: %v\n", ok)
- fmt.Printf("value: %v\n", value)
-
- value2, ok2 := myanimal.(*Dog)
- fmt.Printf("ok: %v\n", ok2)
- fmt.Printf("value: %v\n", value2)
-
- // ok: true
- // value: &{blue}
- // ok: false
- // value: <nil>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。