网站首页 > 文章中心 > 其它

go语言返回任意类型

作者:小编 更新时间:2023-09-26 17:02:25 浏览量:265人看过

golang c.cstring 返回的是什么类型

可以用注释符//和/**/包围C代码

import "C" 和包含C代码之间是没有空行的

动态库的导入和编译选项通过LDFLAGS、CFLAGS/CXXFLAGS来设置

还可以用pkg-config #cgo pkg-config : xxxxname

今天先看看go和c之间的类型转换:

char -- C.char -- byte

go语言string之Buffer与Builder

操作字符串离不开字符串的拼接,但是Go中string是只读类型,大量字符串的拼接会造成性能问题.

拼接字符串,无外乎四种方式,采用"◆","fmt.Sprintf()","bytes.Buffer","strings.Builder"

上面我们创建10万字符串拼接的测试,可以发现"bytes.Buffer","strings.Builder"的性能最好,约是"◆"的1000倍级别.

这是由于string是不可修改的,所以在使用"◆"进行拼接字符串,每次都会产生申请空间,拼接,复制等操作,数据量大的情况下非常消耗资源和性能.而采用Buffer等方式,都是预先计算拼接字符串数组的总长度(如果可以知道长度),申请空间,底层是slice数组,可以以append的形式向后进行追加.最后在转换为字符串.这申请了不断申请空间的操作,也减少了空间的使用和拷贝的次数,自然性能也高不少.

bytes.buffer是一个缓冲byte类型的缓冲器存放着都是byte

是一个变长的 buffer,具有 Read 和Write 方法. Buffer 的 零值 是一个 空的 buffer,但是可以使用,底层就是一个 []byte, 字节切片.

向Buffer中写数据,可以看出Buffer中有个Grow函数用于对切片进行扩容.

从Buffer中读取数据

strings.Builder的方法和bytes.Buffer的方法的命名几乎一致.

但实现并不一致,Builder的Write方法直接将字符拼接slice数组后.

其没有提供read方法,但提供了strings.Reader方式

Reader 结构:

Buffer:

Builder:

可以看出Buffer和Builder底层都是采用[]byte数组进行装载数据.

先来说说Buffer:

创建好Buffer是一个empty的,off 用于指向读写的尾部.

其String()方法就是将字节数组强转为string

Builder是如何实现的.

Builder采用append的方式向字节数组后添加字符串.

其次String()方法与Buffer的string方法也有明显区别.Buffer的string是一种强转,我们知道在强转的时候是需要进行申请空间,并拷贝的.而Builder只是指针的转换.

这里我们解析一下 *(*string)(unsafe.Pointer(b.buf)) 这个语句的意思.

先来了解下unsafe.Pointer 的用法.

也就是说,unsafe.Pointer 可以转换为任意类型,那么意味着,通过unsafe.Pointer媒介,程序绕过类型系统,进行地址转换而不是拷贝.

即*A = Pointer = *B

就像上面例子一样,将字节数组转为unsafe.Pointer类型,再转为string类型,s和b中内容一样,修改b,s也变了,说明b和s是同一个地址.但是对s重新赋值后,意味着s的地址指向了"WORLD",它们所使用的内存空间不同了,所以s改变后,b并不会改变.

所以他们的区别就在于 bytes.Buffer 是重新申请了一块空间,存放生成的string变量, 而strings.Builder直接将底层的[]byte转换成了string类型返回了回来,去掉了申请空间的操作.

go语言的reflect(反射)

①.、反射可以在运行时 动态获取变量的各种信息 ,比如变量的类型、类别;

①.、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射.

例如以下这种桥接模式:

示例第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数.

①.、reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型.

①.、reflect.Value.Kind,获取变量的 类别(Kind) ,返回的是一个 常量 .在go语言文档中:

示例如下所示:

输出如下:

Kind的范畴要比Type大.比如有Student和Consumer两个结构体,他们的 Type 分别是 Student 和 Consumer ,但是它们的 Kind 都是 struct .

如果是x是float类型的话,也是要用reflect.Value(x).Float().但是如果是struct类型的话,由于type并不确定,所以没有相应的方法,只能 断言.

golang中级进阶(二):结构体

目录

第一段:结构体详解

① 结构体定义

第二段:结构体方法

① 结构体的方法定义

第三段:嵌套、继承

① 匿名结构体

第四段:结构体和JSON相互转换

① 结构体转化成json

Golang 中没有"类"的概念,Golang 中的结构体和其他语言中的类有点相似.和其他面向对 象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性.

Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全 部或部分属性时,这时候再用单一的基本数据类型就无法满足需求了,Golang 提供了一种 自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称 struct. 也就是我们可以通过 struct 来定义自己的类型了.

使用 type 和 struct 关键字来定义结构体,具体代码格式如下:

type 类型名 struct {

字段名 字段类型

字段名 字段类型 ...

}

其中:

类型名:表示自定义结构体的名称,在同一个包内不能重复.

字段名:表示结构体字段名.结构体中的字段名必须唯一.

字段类型:表示结构体字段的具体类型.

在 go 语言中,没有类的概念但是可以给类型(结构体,自定义类型)定义方法.所谓方法 就是定义了接收者的函数.接收者的概念就类似于其他语言中的 this 或者 self.

方法的定义格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {

函数体

注意:想改变结构体内的值,必须先变成指针.

在 Go 语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法. 举个例子,我们基于内置的 int 类型使用 type 关键字可以定义新的自定义类型,然后为我们 的自定义类型添加方法.

注意:匿名结构体中不允许出现多个重复的类型

注意:如果结构体里面有私有属性也就是小写定义的字段,则不会被json使用

go语言语法(基础语法篇)

import "workname/packetfolder"

导入多个包

方法调用 包名.函数//不是函数或结构体所处文件或文件夹名

packagename.Func()

前面加个点表示省略调用,那么调用该模块里面的函数,可以不用写模块名称了:

当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已.下划线的作用仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数

import _ package

变量声明必须要使用否则会报错.

全局变量运行声明但不使用.

使用大小来区分函数可见性

大写是public类型

小写是private类型

func prifunc int{}

func pubfunc int{}

声明静态变量

const value int

定义变量

var value int

声明一般类型、接口和结构体

声明函数

func function () int{}

go里面所有的空值对应如下

通道类型

内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针

func new(Type) *Type

[这位博主有非常详细的分析]

Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可.

goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的.

同一个程序中的所有 goroutine 共享同一个地址空间.

语法格式如下:

通道(channel)是用来传递数据的一个数据结构.

通道的声明

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯.操作符 - 用于指定通道的方向,发送或接收.如果未指定方向,则为双向通道.

[这里有比较详细的用例]

go里面的空接口可以指代任何类型(无论是变量还是函数)

声明空接口

go里面的的强制类型转换语法为:

int(data)

如果是接口类型的强制转成其他类型的语法为:

go里面的强制转换是将值复制过去,所以在数据量的时候有比较高的运行代价

golang-redis系列——返回值助手函数(二)

从上一节的内容可知,Do() 和 Receive() 等方法的返回值,除了 error 外,是一个 interface{} 类型的返回值,所以呢当我们的复杂操作返回的不是基本数据类型时,就需要我们自己解析返回值,例如,当我们利用 HMGET 方法获取一批返回值时,就需要对返回结果进行解析,具体如下:

随着我们操作复杂度,数据解析的工作量也会非常大,(lua 脚本的使用,会使结果的解析更为复杂,因为可能存在多种类型的结果一起返回的情况,lua 脚本相关的内容会在下一节介绍).

redigo 包中的返回值助手函数的存在,就是为了帮助我们完成这些枯燥繁琐的数据解析过程.

返回值助手函数相关源码路径为 github.com/gomodule/redigo/redis/reply.go 提供的主要方法如下:

除了使用返回值助手函数对上述固定结构的结果进行解析外,redigo 包还提供了一个 Scan()函数用于解析自定义的复杂数据结构,我们依然以上一个示例进行说明,具体示例如下:

如果返回结果为结构化切片,也可以使用 canSlice() 方法,从而简化 loop 处理的部分,具体示例如下:

如果 value 必须以结构化的数据存储,那么可以提前对要写入的数据进行编码,例如 json、protobuf 等,取出后再进行解码获得原始数据.

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章