• 总结:golang一些常见写法


    一、interface{}

    golang中可以使用interface{}表示任何类型。

    其实和java中的interface几乎一样,也是接口,需要实现类

    二、strconv包

    strconv包实现了基本数据类型与其字符串表示的转换,主要有以下常用函数:
    Atoi()Itia()、parse系列、format系列、append系列。

    案例:

    1. netIf.InBytes, _ = strconv.ParseInt(fields[0], 10, 64)
    2. netIf.InPackages, _ = strconv.ParseInt(fields[1], 10, 64)
    3. netIf.InErrors, _ = strconv.ParseInt(fields[2], 10, 64)
    4. netIf.InDropped, _ = strconv.ParseInt(fields[3], 10, 64)
    5. netIf.InFifoErrs, _ = strconv.ParseInt(fields[4], 10, 64)

    strconv.ParseInt(fields[0], 10, 64):将字符串转为数字,并且限制数字大小不能超过int64的最大值

    golang strconv.ParseInt 是将字符串转换为数字的函数,功能非常强大.

    参数1 数字的字符串形式
    参数2 数字字符串的进制 比如二进制 八进制 十进制 十六进制
    参数3 返回结果的bit大小 也就是int8 int16 int32 int64

    三、io/ioutil包

    读文件,比如linux的一些网卡的监控,需要读取文件:/proc/net/dev

    golang读取:

    1. contents, err := ioutil.ReadFile("/proc/net/dev")
    2. ret := []*NetIf{}
    3. reader := bufio.NewReader(bytes.NewBuffer(contents))
    4. for {
    5. lineBytes, err := file.ReadLine(reader)
    6. line := string(lineBytes)
    7. idx := strings.Index(line, ":")
    8. if idx < 0 {
    9. continue
    10. }
    11. netIf := NetIf{}
    12. eth := strings.TrimSpace(line[0:idx])
    13. if len(onlyPrefix) > 0 {
    14. found := false
    15. for _, prefix := range onlyPrefix {
    16. if strings.HasPrefix(eth, prefix) {
    17. found = true
    18. break
    19. }
    20. }
    21. if !found {
    22. continue
    23. }
    24. }
    25. netIf.Iface = eth
    26. fields := strings.Fields(line[idx+1:])
    27. netIf.InBytes, _ = strconv.ParseInt(fields[0], 10, 64)
    28. netIf.InPackages, _ = strconv.ParseInt(fields[1], 10, 64)
    29. ret = append(ret, &netIf)
    30. }

    四、golang中的strings.Index

    golang字符串操作

    strings.Index(s,str):返回子串str在字符串s中第一次出现的位置。如果找不到则返回-1;如果str为空,则返回0

    1. func main(){
    2. s := "hello world hello world"
    3. str := "wo"
    4. //返回子串str在字符串s中第一次出现的位置。
    5. //如果找不到则返回-1;如果str为空,则返回0
    6. index := strings.Index(s,str)
    7. fmt.Println(index) //6
    8. }

    五、Golang之缓冲器bytes.Buffer

    b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个Buffer

    六、go中string与[]byte的互换

    1、标准转换

    标准转换方式:

    1. // string to []byte
    2. s1 := "hello"
    3. b := []byte(s1)
    4. // []byte to string
    5. s2 := string(b)

    2、强转换

    通过unsafe和reflect包,可以实现另外一种转换方式,我们将之称为强转换(也常常被人称作黑魔法)。

    1. func String2Bytes(s string) []byte {
    2. sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    3. bh := reflect.SliceHeader{
    4. Data: sh.Data,
    5. Len: sh.Len,
    6. Cap: sh.Len,
    7. }
    8. return *(*[]byte)(unsafe.Pointer(&bh))
    9. }
    10. func Bytes2String(b []byte) string {
    11. return *(*string)(unsafe.Pointer(&b))
    12. }

    强转换方式的性能会明显优于标准转换。

    七、字符串截取

    • 可以使用len(字符串变量)获取字符串的字节长度,其中英文占1个字节长度,中文占用3个字节长度

    • 可以使用变量名[n]获取到字符串第n+1个字节,返回这个字节对应的Unicode码值(uint8类型).注意n的取值范围是[0,长度)

    • 可以使用变量名[n:m]取出大于等于n小于m的字符序列

      • n和m都可以省略,省略时认为n为0,m为长度

      • 因为中文占用三个字节,如果没有把中文完整取出,会出现乱码

    1. func main() {
    2. s := "smallming张"
    3. fmt.Println(len(s)) //输出:12,字节长度,注意,中文三个字节
    4. fmt.Println(s[1:4]) //输出:mal
    5. fmt.Println(s[:2]) //输出:sm
    6. fmt.Println(s[5:]) //输出:ming张
    7. }

    八、strings.Fields函数

    以连续的空白字符为分隔符,将s切分成多个子串,结果中不包含空白字符本身。

    返回str的子字符串切片

    1. func main(){
    2. s := "hello world hello world"
    3. //str := "wo"
    4. //以连续的空白字符为分隔符,将s切分成多个子串,结果中不包含空白字符本身。
    5. //空白字符有:\t, \n, \v, \f, \r, ’ ‘, U+0085 (NEL), U+00A0 (NBSP) 。
    6. //如果 s 中只包含空白字符,则返回一个空列表
    7. index := strings.Fields(s)
    8. fmt.Println(len(index)) //4
    9. }

    九、关于生成对象

    我们一般用new或&去生成对象,他们生成的对象就是指针类型

    netIf := &NetIf{}:netIf就是一个指针,指向对象的内存地址

    netIf := NetIf{}:netIf则表示对象本身而不是指针

    但是对netIf的使用上几乎没有区别,那为什么要有两种方式呢?

    主要是指针的话方法传递的时候,直接传递的是指针,这个好处是空间小,尤其是分布式开发的时候,最好用指针

    而调用方法直接传递对象的话就是传递对象本身了,对于分布式方法调用,会导致传递的流量变大

    十、Golang 内置函数:make()

    make() 是 Go 语言内存分配的内置函数,默认有三个参数。

    make(Type, len, cap)
    Type:数据类型,必要参数,Type 的值只能是 slice、 map、 channel 这三种数据类型。
    len:数据类型实际占用的内存空间长度,map、 channel 是可选参数,slice 是必要参数。
    cap:为数据类型提前预留的内存空间长度,可选参数。所谓的提前预留是当前为数据类型申请内存空间的时候,提前申请好额外的内存空间,这样可以避免二次分配内存带来的开销,大大提高程序的性能。

    十一、golang调用函数

    golang中函数可以不属于任何一个结构体,可以用包直接调用,如:

    netIfs, err := nux.NetIfs(ifacePrefix)

    nux是个包,包直接调用了函数,github.com/toolkits/nux

    而Java中必须先创建对象,再通过对象调用函数

    十二、函数名之前指定接收者

    读Grafana mimir源码的时候,看到了如下的函数,func后面跟了一个括号,一开始以为是返回值,但是golang返回值定义在参数后面,后来咨询了下chatgpt。

    原来,这是一个接收者,其实就是什么类型可以调用这个方法,比如下面的函数,其实就是 *Limits的 l ,可以直接调用下面的方法,如本例中:l.unmarshal(func(v any) error {

    1. func (l *Limits) UnmarshalJSON(data []byte) error {
    2.     return l.unmarshal(func(v any) error {
    3.         xxx
    4.     })
    5. }
    6. func (l *Limits) unmarshal(decode func(any) error) error {
    7.     xxx
    8. }

    下面是chatgpt的回答:

    1. Go 语言中,接收者是将方法(成员函数)与特定的数据类型关联起来的一种机制接收者就是方法执行时所作用于的数据类型的实例,可以将其理解为其他面向对象编程语言(如 Java)中的 `this` 或 `self` 关键字
    2. 接收者为函数添加了一个隐式的第一个参数,而这个参数代表了调用此方法的数据类型的实例当你在这个实例上调用方法时,接收者参数会自动传递给该方法
    3. 以下是一个详细解释接收者用法的例子:
    4. ```go
    5. package main
    6. import (
    7. "fmt"
    8. )
    9. // 定义一个简单的结构体,用于表示人的姓名和年龄。
    10. type Person struct {
    11. Name string
    12. Age int
    13. }
    14. // 接收者是 Person 结构的 方法。它在 Person 类型的实例上打印 "Hello" 消息。
    15. func (p Person) SayHello() {
    16. fmt.Println("Hello, my name is", p.Name)
    17. }
    18. // 带有接收者的方法,它在 Person 类型的实例上增加年龄。
    19. func (p *Person) AddAge(years int) {
    20. p.Age += years
    21. }
    22. func main() {
    23. // 创建一个 Person 结构体实例
    24. person := Person{Name: "Alice", Age: 30}
    25. // 使用接收者在 person 实例上调用 SayHello 方法
    26. person.SayHello() // 输出 "Hello, my name is Alice"
    27. // 使用接收者在 person 实例上调用 AddAge 方法
    28. person.AddAge(5) // person.Age 变为 35
    29. fmt.Println("Person after adding 5 years:", person)
    30. }
    31. ```
    32. 在示例中,我们定义了一个名为 `Person` 的结构体,并为其实现了两个方法:`SayHello` 和 `AddAge`这两个方法都具有接收者参数,它们指定了这些方法应作用于哪种数据类型
    33. `SayHello` 方法的接收者是 `Person` 类型,其方法签名为 `func (p Person) SayHello()`这表示只要有一个 `Person` 类型的实例,我们就可以在这个实例上调用 `SayHello` 方法
    34. `AddAge` 方法的接收者是 `*Person` 指针类型,其方法签名为 `func (p *Person) AddAge(years int)`由于接收者类型是指针,当在 `Person` 实例上调用 `AddAge` 方法时,我们可以直接修改这个实例的状态(即修改其 `Age` 属性)
    35. 在 `main` 函数中,我们创建了一个名为 `person` 的 `Person` 类型实例,并在该实例上调用了这两个方法
    36. 总结一下,接收者的用法主要是为了将方法与特定的数据类型关联在方法内部可以通过接收者参数访问和操作数据类型的实例带有接收者的方法可以在其数据类型的实例上调用,接收者参数会自动传入方法内

    十三、结构体定义:标签

    如下结构体第三列,这是golang对结构体的支持,即标签,指从某种格式的文件中获取key对应的value值。

    结构体标签被放置在反引号 (``) 中,紧跟字段类型之后。标签的格式通常是 `key:"value"`

    key如JSON、YAML、XML 等。

    以下定义了yaml和json两个,即从yaml中取或从json中取request_rate的值。

    1. type Limits struct {
    2. // Distributor enforced limits.
    3. RequestRate float64 `yaml:"request_rate" json:"request_rate" category:"experimental"`
    4. RequestBurstSize int `yaml:"request_burst_size" json:"request_burst_size" category:"experimental"`
    5. IngestionRate float64 `yaml:"ingestion_rate" json:"ingestion_rate"`
    6. }

  • 相关阅读:
    无监督学习
    电脑访问不到在同网络的手机设备
    stm32之看门狗
    原创 | Pro无法与arcgis.com连接
    linux之chmod命令
    SpringBoot+SpringMVC+MybatisPlus
    Unity DOTS World Entity ArchType Component EntityManager System概述
    Linux之IO多路复用
    一个手机ip从这个城市去到另一个城市多久会变
    极智资讯 | 一文看尽今年的云栖大会 有哪些好玩的
  • 原文地址:https://blog.csdn.net/w2009211777/article/details/127090008