码迷,mamicode.com
首页 > 其他好文 > 详细

[go]strings.go

时间:2020-01-05 20:27:56      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:info   ext   range   而不是   通过   为什么   ntp   大小   href   

参考

//builtin包对string的描述

// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string

- 默认零值是"" , 而不是nil
- 不可变(值存储在只读内存区)
- stings数据结构的定义: 
src/runtime/string.go: stringStruct (对外呈现string)

type stringStruct struct {
    str unsafe.Pointer  //str首地址
    len int             //str长度
}
// str构造过程: 先构造stringStruct,然后将stringStruct转为str返回

var s string
s = "mao"

func gostringnocopy(str *byte) string { // 跟据字符串地址构建string
    ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} // 先构造stringStruct
    s := *(*string)(unsafe.Pointer(&ss))                             // 再将stringStruct转换成string
    return s
}
// []byte转string(转换需要一次内存拷贝)

func GetStringBySlice(s []byte) string {
    return string(s)
}

1. 根据切片长度申请足够内存地址空间
2. 构建string
3. 拷贝数据
// string转换[]byte(转换需要一次内存拷贝)


func GetSliceByString(str string) []byte {
    return []byte(str)
}

1.申请内存地址空间
2.拷贝数据
// 字符串拼接
str := "Str1" + "Str2" + "Str3"

性能较好: 
    新字符串的内存空间是一次分配完成的,
    所以性能消耗主要在拷贝数据上。

一个拼接语句的字符串编译时都会被存放到一个切片中,拼接过程需要遍历两次切片,
    1. 第一次遍历获取总的字符串长度,据此申请内存,
    2. 第二次遍历会把字符串逐个拷贝过去。

func concatstrings(a []string) string { // 字符串拼接
    length := 0        // 拼接后总的字符串长度

    for _, str := range a {
        length += length(str)
    }
    s, b := rawstring(length) // 生成指定大小的字符串,返回一个string和切片,二者共享内存空间

    for _, str := range a {
        copy(b, str)    // string无法修改,只能通过切片修改
        b = b[len(str):]
    }
    
    return s
}



func rawstring(size int) (s string, b []byte) { // 生成一个新的string,返回的string和切片共享相同的空间
    p := mallocgc(uintptr(size), nil, false)

    stringStructOf(&s).str = p
    stringStructOf(&s).len = size

    *(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}

    return
}
// 为什么字符串不允许修改?
像C++语言中的string,其本身拥有内存空间,修改string是支持的。
但Go的实现中,string**不包含内存空间,只有一个内存的指针**,
这样做的好处是string变得非常轻量,可以很方便的进行传递而不用担心内存拷贝。

因为string通常指向字符串字面量,**而字符串字面量存储位置是只读段,而不是堆或栈上,**
所以才有了string不可修改的约定。

技术图片

[go]strings.go

标签:info   ext   range   而不是   通过   为什么   ntp   大小   href   

原文地址:https://www.cnblogs.com/iiiiiher/p/12153429.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!