golanglen()的简单介绍

本文目录一览:

如何将任意Golang接口转换为字节数组

golang语言本身就是c的工具集,开发c的程序用到的大部分结构体,内存管理,携程等,golang基本都有,他只是在这个基础上又加了一些概念这里说一个很小的问题,就是字节数组转string的问题,网上大部分都是这样转的(包括google上):string(p[:]),这个转完了是有问题的,我们再来看一下string这个结构体:

struct String

{

byte* str;

intgo len;

};

这个结构体让我想起了nginx的string,他是这样定义的:

typedef struct {

size_t len;

u_char *data;

} ngx_str_t;

golang里边 string的概念其实不是以前遇到\0结尾的概念了,他其实就是一块连续的内存,首地址+长度,上面那样赋值,如果p里边有\0,他不会做处理这个时候,如果再对这个string做其他处理就可能出问题了,比如strconv.Atoi转成int就有错误,解决办法就是需要自己写一个正规的转换函数:

func byteString(p []byte) string {

for i := 0; i len(p); i++ {

if p[i] == 0 {

return string(p[0:i])

}

}

return string(p)

}

这样就不会出问题了

golang正则表达式 分组命名

正则中有分组这个功能,在golang中也可以使用命名分组。

一次匹配的情况

场景还原如下:

有一行文本,格式为:姓名 年龄 邮箱地址

请将其转换为一个map

代码实现如下:

str := `Alice 20 alice@gmail.com`

// 使用命名分组,显得更清晰

re := regexp.MustCompile(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\w+@\w+(?:\.\w+)+)`)

match := re.FindStringSubmatch(str)

groupNames := re.SubexpNames()

fmt.Printf(“%v, %v, %d, %d\n”, match, groupNames, len(match), len(groupNames))

result := make(map[string]string)

// 转换为map

for i, name := range groupNames {

if i != 0 name != “” { // 第一个分组为空(也就是整个匹配)

result[name] = match[i]

}

}

prettyResult, _ := json.MarshalIndent(result, “”, ” “)

fmt.Printf(“%s\n”, prettyResult)

输出为:

[Alice 20 alice@gmail.com Alice 20 alice@gmail.com], [ name age email], 4, 4

{

“age”: “20”,

“email”: “alice@gmail.com”,

“name”: “Alice”

}

注意 [ name age email]有4个元素, 第一个为””。

多次匹配的情况

接上面的例子,实现一个更贴近现实的需求:

有一个文件, 内容大致如下:

Alice 20 alice@gmail.com

Bob 25 bob@outlook.com

gerrylon 26 gerrylon@github.com

更多内容

和上面一样, 不过这次转出来是一个slice of map, 也就是多个map。

代码如下:

// 文件内容直接用字符串表示

usersStr := `

Alice 20 alice@gmail.com

Bob 25 bob@outlook.com

gerrylon 26 gerrylon@github.com

`

userRe := regexp.MustCompile(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\w+@\w+(?:\.\w+)+)`)

// 这里要用FindAllStringSubmatch,找到所有的匹配

users := userRe.FindAllStringSubmatch(usersStr, -1)

groupNames := userRe.SubexpNames()

var result []map[string]string // slice of map

// 循环所有行

for _, user := range users {

m := make(map[string]string)

// 对每一行生成一个map

for j, name := range groupNames {

if j != 0 name != “” {

m[name] = strings.TrimSpace(user[j])

}

}

result = append(result, m)

}

prettyResult, _ := json.MarshalIndent(result, “”, ” “)

fmt.Println(string(prettyResult))

输出为:

[

{

“age”: “20”,

“email”: “alice@gmail.com”,

“name”: “Alice”

},

{

“age”: “25”,

“email”: “bob@outlook.com”,

“name”: “Bob”

},

{

“age”: “26”,

“email”: “gerrylon@github.com”,

“name”: “gerrylon”

}

]

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

总结

使用命名分组可以使正则表示的意义更清晰。

转换为map更加符合人类的阅读习惯,不过比一般的根据索引取分组值麻烦一些。

————————————————

版权声明:本文为CSDN博主「butterfly5211314」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:

golang怎么返回结构体

用golang解析二进制协议时,其实没必要管结构体的字段的对齐规则,何况语言规范也没有规定如何对齐,也就是没有规则。用encoding/binary.Read函数直接读入struct里就行,struct就像c那样写

type Data struct {

Size, MsgType uint16

Sequence uint32

// …

}

golang编译器加不加padding,Read都能正常工作,runtime知道Data的布局的,不像C直接做cast所以要知道怎样对齐。

用unsafe.Alignof可以知道每个field的对齐长度,但没必要用到。

package main

/*

#include stdint.h

#pragma pack(push, 1)

typedef struct {

uint16_t size;

uint16_t msgtype;

uint32_t sequnce;

uint8_t data1;

uint32_t data2;

uint16_t data3;

} mydata;

#pragma pack(pop)

mydata foo = {

1, 2, 3, 4, 5, 6,

};

int size() {

return sizeof(mydata);

}

*/

import “C”

import (

“bytes”

“encoding/binary”

“fmt”

“log”

“unsafe”

)

func main() {

bs := C.GoBytes(unsafe.Pointer(C.foo), C.size())

fmt.Printf(“len %d data %v\n”, len(bs), bs)

var data struct {

Size, Msytype uint16

Sequence uint32

Data1 uint8

Data2 uint32

Data3 uint16

}

err := binary.Read(bytes.NewReader(bs), binary.LittleEndian, data)

if err != nil {

log.Fatal(err)

}

fmt.Printf(“%v\n”, data) // {1 2 3 4 5 6}

buf := new(bytes.Buffer)

binary.Write(buf, binary.BigEndian, data)

fmt.Printf(“%d %v\n”, buf.Len(), buf.Bytes()) // 15 [0 1 0 2 0 0 0 3 4 0 0 0 5 0 6]

}

GoLang中的切片扩容机制

[5]int 是数组,而 []int 是切片。二者看起来相似,实则是根本上不同的数据结构。

切片的数据结构中,包含一个指向数组的指针 array ,当前长度 len ,以及最大容量 cap 。在使用 make([]int, len) 创建切片时,实际上还有第三个可选参数 cap ,也即 make([]int, len, cap) 。在不声明 cap 的情况下,默认 cap=len 。当切片长度没有超过容量时,对切片新增数据,不会改变 array 指针的值。

当对切片进行 append 操作,导致长度超出容量时,就会创建新的数组,这会导致和原有切片的分离。在下例中

由于 a 的长度超出了容量,所以切片 a 指向了一个增长后的新数组,而 b 仍然指向原来的老数组。所以之后对 a 进行的操作,对 b 不会产生影响。

试比较

本例中, a 的容量为6,因此在 append 后并未超出容量,所以 array 指针没有改变。因此,对 a 进行的操作,对 b 同样产生了影响。

下面看看用 a := []int{} 这种方式来创建切片会是什么情况。

可以看到,空切片的容量为0,但后面向切片中添加元素时,并不是每次切片的容量都发生了变化。这是因为,如果增大容量,也即需要创建新数组,这时还需要将原数组中的所有元素复制到新数组中,开销很大,所以GoLang设计了一套扩容机制,以减少需要创建新数组的次数。但这导致无法很直接地判断 append 时是否创建了新数组。

如果一次添加多个元素,容量又会怎样变化呢?试比较下面两个例子:

那么,是不是说,当向一个空切片中插入 2n-1 个元素时,容量就会被设置为 2n 呢?我们来试试其他的数据类型。

可以看到,根据切片对应数据类型的不同,容量增长的方式也有很大的区别。相关的源码包括: src/runtime/msize.go , src/runtime/mksizeclasses.go 等。

我们再看看切片初始非空的情形。

可以看到,与刚刚向空切片添加5个int的情况一致,向有3个int的切片中添加2个int,容量增长为6。

需要注意的是, append 对切片扩容时,如果容量超过了一定范围,处理策略又会有所不同。可以看看下面这个例子。

具体为什么会是这样的变化过程,还需要从 源码 中寻找答案。下面是 src/runtime/slice.go 中的 growslice 函数中的核心部分。

GoLang中的切片扩容机制,与切片的数据类型、原本切片的容量、所需要的容量都有关系,比较复杂。对于常见数据类型,在元素数量较少时,大致可以认为扩容是按照翻倍进行的。但具体情况需要具体分析。

golang变量(二)——map和slice详解

衍生类型,interface{} , map, [] ,struct等

map类似于java的hashmap,python的dict,php的hash array。

常规的for循环,可以用for k,v :=range m {}. 但在下面清空有一个坑注意:

著名的map[string]*struct 副本问题

结果:

Go 中不存在引用传递,所有的参数传递都是值传递,而map是等同于指针类型的,所以在把map变量传递给函数时,函数对map的修改,也会实质改变map的值。

slice类似于其他语言的数组(list,array),slice初始化和map一样,这里不在重复

除了Pointer数组外,len表示使用长度,cap是总容量,make([]int, len, cap)可以预申请 比较大的容量,这样可以减少容量拓展的消耗,前提是要用到。

cap是计算切片容量,len是计算变量长度的,两者不一样。具体例子如下:

结果:

分析:cap是计算当前slice已分配的容量大小,采用的是预分配的伙伴算法(当容量满时,拓展分配一倍的容量)。

append是slice非常常用的函数,用于添加数据到slice中,但如果使用不好,会有下面的问题:

预期是[1 2 3 4 5 6 7 8 9 10], [1 2 3 4 5 6 7 8 9 10 11 12],但实际结果是:

注意slice是值传递,修改一下:

输出如下:

== 只能用于判断常规数据类型,无法使用用于slice和map判断,用于判断map和slice可以使用reflect.DeepEqual,这个函数用了递归来判断每层的k,v是否一致。

当然还有其他方式,比如转换成json,但小心有一些异常的bug,比如html编码,具体这个json问题,待后面在分析。

如何理解Golang中的range语句

你把它理解为遍历么,结合for循环。

假设有一个初始化好的数组(table)或者切片(slice)的table,且table长度为10:

for i, value := range table {

    fmt.Printf(“i=%v, value=%v\n”, i, value)

}

则会执行fmt.Printf10次,且这10次的【i】的值分别是从0~9,也就相当于

for i := 0; i  len(table); i++ {

    fmt.Printf(“i=%v, value=%v\n”, i, table[i])

}

如果把上边的数组或者切片换成map

for key, value := range table {

    fmt.Pritnf(“key=%v, value=%v\n”, key, value)

}

则类似上边的过程把map里边的key-value键值对一 一遍历

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/227777.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝的头像小蓝
上一篇 2024-12-09 16:32
下一篇 2024-12-09 21:21

相关推荐

  • Python简单数学计算

    本文将从多个方面介绍Python的简单数学计算,包括基础运算符、函数、库以及实际应用场景。 一、基础运算符 Python提供了基础的算术运算符,包括加(+)、减(-)、乘(*)、除…

    编程 2025-04-29
  • Python满天星代码:让编程变得更加简单

    本文将从多个方面详细阐述Python满天星代码,为大家介绍它的优点以及如何在编程中使用。无论是刚刚接触编程还是资深程序员,都能从中获得一定的收获。 一、简介 Python满天星代码…

    编程 2025-04-29
  • Python海龟代码简单画图

    本文将介绍如何使用Python的海龟库进行简单画图,并提供相关示例代码。 一、基础用法 使用Python的海龟库,我们可以控制一个小海龟在窗口中移动,并利用它的“画笔”在窗口中绘制…

    编程 2025-04-29
  • Python樱花树代码简单

    本文将对Python樱花树代码进行详细的阐述和讲解,帮助读者更好地理解该代码的实现方法。 一、简介 樱花树是一种图形效果,它的实现方法比较简单。Python中可以通过turtle这…

    编程 2025-04-28
  • Python大神作品:让编程变得更加简单

    Python作为一种高级的解释性编程语言,一直被广泛地运用于各个领域,从Web开发、游戏开发到人工智能,Python都扮演着重要的角色。Python的代码简洁明了,易于阅读和维护,…

    编程 2025-04-28
  • 用Python实现简单爬虫程序

    在当今时代,互联网上的信息量是爆炸式增长的,其中很多信息可以被利用。对于数据分析、数据挖掘或者其他一些需要大量数据的任务,我们可以使用爬虫技术从各个网站获取需要的信息。而Pytho…

    编程 2025-04-28
  • 如何制作一个简单的换装游戏

    本文将从以下几个方面,为大家介绍如何制作一个简单的换装游戏: 1. 游戏需求和界面设计 2. 使用HTML、CSS和JavaScript开发游戏 3. 实现游戏的基本功能:拖拽交互…

    编程 2025-04-27
  • Guava Limiter——限流器的简单易用

    本文将从多个维度对Guava Limiter进行详细阐述,介绍其定义、使用方法、工作原理和案例应用等方面,并给出完整的代码示例,希望能够帮助读者更好地了解和使用该库。 一、定义 G…

    编程 2025-04-27
  • 2的32次方-1:一个看似简单却又复杂的数字

    对于计算机领域的人来说,2的32次方-1(也就是十进制下的4294967295)这个数字并不陌生。它经常被用来表示IPv4地址或者无符号32位整数的最大值。但实际上,这个数字却包含…

    编程 2025-04-27
  • 制作一个简单的管理系统的成本及实现

    想要制作一个简单的管理系统,需要进行技术选型、开发、测试等过程,那么这个过程会花费多少钱呢?我们将从多个方面来阐述制作一个简单的管理系统的成本及实现。 一、技术选型 当我们开始思考…

    编程 2025-04-27

发表回复

登录后才能评论