Golang的基本使用

目录

变量的声明

Golang常用容器

defer

有趣的多态

结构体标签和reflect 反射

Golang最强的协程

channel

go可能造成的内存泄露

变量的声明

方法 1:有类型,有var,不赋值 在Golang中默认值为0

方法 2:无类型,有var,赋值

方法 3:无类型,无var,赋值

多变量声明

多变量声明,无类型无var

如下

package main

import (
	"fmt"
)

func main() {
	//var 用于声明变量
	var a int // 方法 1:有类型,有var,不赋值 在Golang中默认值为0
	fmt.Println("a=", a)

	var b = 0 //方法 2:无类型,有var,赋值
	fmt.Println("b=", b)

	c := 0 //方法 3:无类型,无var,赋值
	fmt.Println("c=", c)

	//多变量声明
	var d, e int = 1, 2 //
	fmt.Println("d=", d, "e=", e)

	//多变量声明,无类型无var
	f, g := "string", 3
	fmt.Println("f=", f, "e=", g)

}

常量 

定义后无法改变

Golang常用容器

静态数组(slice)

package main

import "fmt"

func main() {

	//数组,静态数组
	var arr [5]int
	arr[0] = 1
	arr[1] = 2
	arr[2] = 3
	arr[3] = 4
	arr[4] = 5
	fmt.Println(arr)      // 输出: [1 2 3 4 5]
	fmt.Println(len(arr)) // 输出: 5

}

动态数组(array)

跟静态数组的区别,就是 不用规定数组大小,自动分配自动扩容

package main

import "fmt"

func main() {
	//跟静态数组的区别,就是 不用规定数组大小,自动分配自动扩容
	slice := []int{1, 2, 3, 4, 5}
	fmt.Println(slice)      // 输出: [1 2 3 4 5]
	fmt.Println(len(slice)) // 输出: 5
}

自动扩容演示

slice两倍扩容

package main

import "fmt"

func main() {
	//跟静态数组的区别,就是 不用规定数组大小,自动分配自动扩容
	slice := []int{1, 2, 3, 4, 5}
	fmt.Println(slice)      // 输出: [1 2 3 4 5]
	fmt.Println(len(slice)) // 输出: 5
	fmt.Println(cap(slice)) //当前容量为5

	slice = append(slice, 6)
	fmt.Println(len(slice)) // 输出: 数据数量=6
	fmt.Println(cap(slice)) // 输出: 10 slice两倍扩容
}

字符串(string)

package main

import "fmt"

func main() {
	str := "Hello, World!"
	fmt.Println(str)         // 输出: Hello, World!
	fmt.Println(len(str))    // 输出: 13
	fmt.Printf("%s", str[0]) // 输出: H 
}

映射(map)

package main

import "fmt"

func main() {
	m := make(map[int]string)
	m[1] = "apple"
	m[2] = "banana"
	m[3] = "orange"
	for i := 1; i < 4; i++ {
		fmt.Printf("m=%s\n", m[i])
	}
}

defer

类似c++中的析构函数

defer作用:

        释放占用的资源

        捕捉处理异常

        输出日志

func main() {
	defer func() {
		fmt.Println("析构函数")
	}()
	fmt.Println("main start")
	//===
	//业务
	//===
	fmt.Println("main off")
}

当然Golang中有资源自动回收,不用自己析构,当然有特殊的例子下面讲了协程再说

有趣的多态

import "fmt"

// 两个类
type Student struct {
	age int
}

type Programmer struct {
	age int
}

// 同一调用
func whatJob(p Person) {
	p.job()
}

func growUp(p Person) {
	p.growUp()
}

// 一个万能接口
type Person interface { //intetface 万能变量
	job()
	growUp()
}

// Student 函数方法
func (p Student) job() {
	fmt.Println("I am a student.")
	return
}

func (p *Student) growUp() {
	p.age += 1
	return
}

// Programmer 函数方法
func (p Programmer) job() {
	fmt.Println("I am a programmer.")
	return
}

func (p *Programmer) growUp() {
	p.age += 10
	return
}

func main() {
	qcrao := Student{age: 18}
	whatJob(&qcrao)

	growUp(&qcrao)
	fmt.Println(qcrao)

	stefno := Programmer{age: 100}
	whatJob(&stefno)

	growUp(&stefno) //同一个函数,调用结果不同
	fmt.Println(stefno)
}

结构体标签和reflect 反射

import (
	"fmt"
	"reflect"
)

type resume struct {
	Name string `json:"电影" doc:"喜剧之王"`
}

func findDoc(stru interface{}) map[string]string {
	t := reflect.TypeOf(stru).Elem() //reflect 反射 逆推类型
	doc := make(map[string]string)

	for i := 0; i < t.NumField(); i++ {
		doc[t.Field(i).Tag.Get("json")] = t.Field(i).Tag.Get("doc")
	}

	return doc

}

func main() {
	var stru resume
	doc := findDoc(&stru)
	fmt.Printf("电影字段=%s\n", doc["电影"])
}

Golang最强的协程

package main

import (
	"fmt"
	"time"
)

func main() {
	go func() {
		fmt.Println("我是协程")
	}()

	fmt.Println("我是主协程")

	time.Sleep(1 * time.Second) // 等待一秒钟,让协程有足够的时间执行
}

身为一个cpp学者,当看见Golang写协程那么方便,异常兴奋

那么协程用什么与主协程通信呢?

channel

管道(channel)接收和发送数据都是阻塞的

package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan int) //创建管道(channel),而且接收和发送数据都是阻塞的
	go func() {
		fmt.Println("我是协程")
		c <- 666 //向管道内写入666
	}()

	a := <-c //管道类读出
	fmt.Println("我是主协程")
	fmt.Println("a=", a)

	time.Sleep(1 * time.Second) // 等待一秒钟,让协程有足够的时间执行
}

go可能造成的内存泄露

func main() {
    ch := func() <-chan int {
        ch := make(chan int)
        go func() {
            for i := 0; ; i++ {
                ch <- i
            }
        } ()
        return ch
    }()

    for v := range ch {
        fmt.Println(v)
        if v == 5 {
            break
        }
    }
}

使用 valgrind 运行 程序,发现 协程内存并没有回收

问题:

上面的程序中后台Goroutine向管道输入自然数序列,main函数中输出序列。

但是当break跳出for循环的时候,后台Goroutine就处于无法被回收的状态了。

因为 Goroutine还在向管道中写数据,主协程已经退出

改正:

使用context

package main

import (
	"context"
	"fmt"
)

func main() {
	//WithCancel(ctx Context, cancel CancelFunc)=(名 Context,处理函数 CancelFunc)
	ctx, cancel := context.WithCancel(context.Background()) //context.Background() 处理 Goroutine

	ch := func(ctx context.Context) <-chan int {
		ch := make(chan int)
		go func() {
			for i := 0; ; i++ {
				select {
				case <-ctx.Done():
					return
				case ch <- i:
				}
			}
		}()
		return ch
	}(ctx)

	for v := range ch {
		fmt.Println(v)
		if v == 5 {
			cancel()
			break
		}
	}
}

当main函数在break跳出循环时,通过调用 context 来通知后台Goroutine退出

这样就避免了Goroutine的泄漏。 

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]提供了关于Golang的四大数据类型及基本类型的介绍。其中,基本类型包括数字类型、布尔型和字符串类型。数字类型包括整型和浮点型,还有其他数字类型。布尔型的值只能是常量true或false。字符串类型分为解释字符串和非解释字符串。引用\[2\]进一步解释了Golang基本类型、复合类型、引用类型和接口类型。基本类型包括数字、字符串和布尔型。复合类型包括数组和结构体,用于表示更复杂的数据结构。引用类型包括指针、切片、映射、通道、接口和函数类型。引用类型的变量被称为标头值。字符串也是一种引用类型。引用\[3\]提到了Golang常量的特点。虽然常量可以有确定的基本类型,但许多常量没有明确的基本类型。编译器为这些常量提供了比基本类型更高精度的算术运算。无类型的常量包括无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数和无类型的字符串。无类型的常量不仅提供更高的运算精度,还可以直接用于更多的表达式而不需要显式的类型转换。 所以,Golang基本数据类型包括数字类型、布尔型和字符串类型。同时,Golang还有复合类型、引用类型和接口类型。 #### 引用[.reference_title] - *1* *2* [Golang数据类型](https://blog.csdn.net/MatChen/article/details/114639964)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Golang(六)[基础数据类型]](https://blog.csdn.net/weixin_42366378/article/details/105003056)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值