按值传递函数参数,是拷贝参数的实际值到函数的形式参数的方法调用.在这种情况下,参数在函数内变化对参数不会有影响.
默认情况下,Go编程语言使用调用通过值的方法来传递参数.在一般情况下,这意味着,在函数内码不能改变用来调用所述函数的参数.考虑函数swap()的定义如下.
代码如下:
/* function definition to swap the values */
func swap(int x, int y) int {
var temp int
temp = x /* save the value of x */
x = y /* put y into x */
y = temp /* put temp into y */
return temp;
}
现在,让我们通过使实际值作为在以下示例调用函数swap():
package main
import "fmt"
func main() {
/* local variable definition */
var a int = 100
fmt.Printf("Before swap, value of a : %d\n", a )
fmt.Printf("Before swap, value of b : %d\n", b )
/* calling a function to swap the values */
swap(a, b)
fmt.Printf("After swap, value of a : %d\n", a )
fmt.Printf("After swap, value of b : %d\n", b )
func swap(x, y int) int {
让我们把上面的代码放在一个C文件,编译并执行它,它会产生以下结果:
Before swap, value of a :100
After swap, value of a :100
这表明,参数值没有被改变,虽然它们已经在函数内部改变.
通过传递函数参数,即是拷贝参数的地址到形式参数的参考方法调用.在函数内部,地址是访问调用中使用的实际参数.这意味着,对参数的更改会影响传递的参数.
要通过引用传递的值,参数的指针被传递给函数就像任何其他的值.所以,相应的,需要声明函数的参数为指针类型如下面的函数swap(),它的交换两个整型变量的值指向它的参数.
func swap(x *int, y *int) {
temp = *x /* save the value at address x */
*x = *y /* put y into x */
*y = temp /* put temp into y */
现在,让我们调用函数swap()通过引用作为在下面的示例中传递数值:
/* calling a function to swap the values.
* a indicates pointer to a ie. address of variable a and
* b indicates pointer to b ie. address of variable b.
*/
*x = *y /* put y into x */
After swap, value of b :100
这表明变化的功能以及不同于通过值调用的外部体现的改变不能反映函数之外.
因为char *strings[]不是指针而是指针数组,那么
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
这种交换交换的就是主调函数中的数组中的指针,把指向字符串的指针顺序改变了,当然按次序输出就达到排序目的了......
①.、数组是多个 相同类型 的数据的组合,一个数组一旦声明/定义了,其 长度是固定的,不能动态变化 .
? ? ? 数值类型数组:?默认值为 0
? ? ? 字符串数组:? ? ? ?默认值为 ""
? ? ? bool数组:? ? ? ? ? ?默认值为 false
? ? ? (1)声明数组并开辟空间
①.0、长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度,看以下案例:
首先说一下go中的字符串类型:
下面介绍字符串的三种遍历方式,根据实际情况选择即可.
该遍历方式==缺点==:遍历是按照字节遍历,所以呢如果有中文等非英文字符,就会出现乱码,比如要遍历"abc北京"这个字符串,效果如下:
该方式是按照字符遍历的,所以不会出现乱码,如下:
运行结果:
由于下标的不确定性,所以引出了下面的遍历方式.
①. 可以先将字符串转成 []rune 切片
运行效果:
由此可见下标是按1递增的,没有产生跳跃现象.
操作字符串离不开字符串的拼接,但是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语言组合字符串操作相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!