Golang——string

本文探讨了Golang中string的结构,强调其不可变性,并介绍了如何进行string与[]byte及int之间的转换。讨论了在string上进行部分反转的挑战,以及在处理中文字符时的注意事项。此外,还提到了在LeetCode问题中遇到的关于字符串操作的陷阱,如strconv.Itoa和sort.Slice的使用。最后,列举了一些常用的Golang string函数及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.string结构体底层
由两部分组成:指向底层[ ]byte数组的指针;长度。(类似切片结构体)

2.相同的string常量不会重复存储

//由s1、s2的指针指向一块相同的只读内存,这段内存以utf-8编码存放hello数组
s1 := "hello"
s2 := "hello"

3.string常量会在编译期分配到只读段,对应数据地址不可写入,故string不支持修改。
要修改必须转[]byte,string和[]byte转换,会将这段只读内存的数据复制到堆/栈上。

//wrong
s := "hello"
s[0] = 'A'
//right
s := "hello"
a := []byte(s)
a[0] = 'H'
s = string(a)    //s="Hello"
package main

import "fmt"

/go的本质是值拷贝,但string底层是指针
/故 函数参数变量s也是一段新地址,但是底层指针指向的地址与main中s相同,为存储数据的空间
func change(s string) string {
	fmt.Printf("%#v\n", &s)
	a := []byte(s)
	a[0] = 's'
	return string(a)
}

func main() {
	s := "abcd"
	fmt.Printf("%#v\n", &s)
	s2 := change(s)
	fmt.Printf("%#v\n", &s2)
}

在这里插入图片描述

整体反转可以整体转为[]byte,不能把string类型作为参数直接传进来
Q:那怎么在原字符串上进行 部分反转?
输入: “abcd”
输出:“acbd”

部分反转错误解法,change返回的是“cb”,而不是“acbd”
func main()  {
	s := "abcd"
	s = change(s[1:3])
	fmt.Println(s)
}
func change(s string) string {
	a := []byte(s)
	i := 0
	j := len(a)-1
	for i < j {
	   a[i],a[j] = a[j],a[i]
	}
	return string(a)
}
反转正确解法
1.
func main()  {
	s := "abcd"
	a := []byte(s)
	change(a,1,2)
	fmt.Println(a)
}
func change(a  []byte,i int, j int) {
	for i < j {
	   a[i],a[j] = a[j],a[i]
	   i++
	   j--
	}
}

2.
func main()  {
	s := "abc"
	a := []byte(s)
	change(a)
	fmt.Println(string(a))
}
func change(a string) {
	i := 0
	j := len(a)-1
	for i < j {
	   a[i],a[j] = a[j],a[i]
	   i++
	   j--
	}
}
leetcode:1143
谨记,string类型的变量,其s[i]byte = uint8类型,只能往同类型[]byte中添加

s := "abc"
fmt.Printf("%T s[0] = \n",s[0],s[0])
//输出结果如下:
uint8 s[0]=90


大坑:对string for range后,类型是int32,即rune !!
s := "("
for _,v := range s {
    fmt.Printf("%T",v)
}
//输出结果如下:
int32 

leetcode:150
s := []string{"2", "1", "+", "3", "*"}
fmt.Printf("%T\n",s[0])
//输出结果如下:
s[0]的类型是string

s := "abc"
fmt.Printf("%T\n",s[1]-'a')
fmt.Println(s[1]-'a ')
//输出结果如下:
uint8 // = byte
1

4.string与int的转换

注意:strconv.Atoi返回值是两个,strconv.Itoa返回值是一个
strconv.Atoi(string) (int,err)
strconv.Itoa(int) string

leetcode:412

//1.right string转成int   
str := "123"
int, err := strconv.Atoi(str) //to int 参数必须是string

str := "123"
int, err := strconv.Atoi(str[0]) ////wrong 此处参数是byte
int, err := strconv.Atoi(string(str[0])) //right

//string转成int
Question : Int(s[0]-'0')  //得到数字1

//2.int转成string
i := 1
str := strconv.Itoa(i)

//3.ASCII转成string
s := "hello" 
fmt.Println(s[0])           //得到ASCII,是byte类型,即uint8。byte等价于uint8,只是用byte来说明这是一个字符的ASCII数字
fmt.Println(string(s[0]))  //得到 "h"

大坑:单引号在 Golang 表示一个字符,使用一个特殊类型 rune 表示字符型。rune 为 int32 的别名,它完全等价于 int32

wrong! a的类型是int32,s[0]的类型是uint8 byte,无法赋值给a
a := 'c'
s := "bcd"
a = s[0]
lc 443
intbyte直接转好像是错的
a := 15
b := byte(a)  //=unit
负数的stringint64
s := "-11"
n,err := strconv.ParseInt(s, 0, 64) //s可以转时,err=nil
fmt.Println("n = ",n)  // n = -11
fmt.Println(err)       // err = nil
fmt.Printf("%T\n",n)  //  int64

5.string中含中文
utf-8编码时,每个中文占3个字节,英文占1个字节

s := "abc中国"
len(s)          //=9,len求的是底层所占字节数
len([]rune(s)) //=5,[]rune会将utf-8编码转为unicode编码

6.对string进行for range循环,返回的value是rune类型

s := "我是中国人c"
for index, runeValue := range s {
		fmt.Printf("%#U 起始于字位置%d\n", runeValue, index)
}

// 输出结果如下:
我 起始于字位置0
是 起始于字位置3
中 起始于字位置6
国 起始于字位置9
人 起始于字位置12
c  起始于字位置13

7.排序 https://learnku.com/articles/38269

1.针对切片排序
s := []string{"abc","def","acd"}
sort.Ints(a)
sort.Strings(s)

2.针对字符串排序 leetcode:49
str := "cab" //想得到“abc”
1)leetcode:4956
mybyte := []byte(str)
sort.Slice(mybyte, func(i, j int) bool { return bytes[i] < bytes[j]}) 

2)
type mybyte []byte //类型定义
func (b mybytes) Len() int {
    return len(b)
}
func (b mybyte) Less(i,j int) bool {
    return b[i] < b[j]
}
func (b mybyte) Swap(i, j int) {
    b[i], b[j] = b[j], b[i]
}
k := mybyte(str)
sort.Sort(k)

79.拼接得到最大值
输入:nums = [3,30,34,5,9]
输出:“9534330”
注意:
1)strconv.Itoa,不是strings.
2) sort.Slice整体用法,括号位置+记得return

func largestNumber(nums []int) string {
   ans := []string{}
   for _,num := range nums {
       ans = append(ans,strconv.Itoa(num))
   }
   sort.Slice(ans,func (i,j int) bool {
       return ans[i]+ans[j] > ans[j]+ans[i]
   })
   if ans[0] == "0" {
       return "0"
   }
   res := ""
   for _,v := range ans {
       res += v
   }
   return res
}
package sort
type Interface interface {
    Len() int            // 获取元素数量
    Less(i, j int) bool // i,j是序列元素的指数。
    Swap(i, j int)        // 交换元素
}
/* 定义接口 */
type interface_name interface {
   method_name1 [return_type]
   method_name2 [return_type]
}

/* 定义结构体 */
type struct_name struct {
     ...
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {
     ...
}
func (struct_name_variable struct_name) method_name2() [return_type] {
    ...
}

Go语言的 sort.Sort 函数不会对具体的序列和它的元素做任何假设。相反,它使用了一个接口类型 sort.Interface 来指定通用的排序算法和可能被排序到的序列类型之间的约定。为了对序列进行排序,我们需要定义一个实现了这三个方法的类型,然后对这个类型的一个实例应用 sort.Sort 函数
为了让 sort 包能识别 mybyte,能够对 mybyte 进行排序,就必须让mybyte实现 sort.Interface 接口,一个类型实现接口=该类型实现sort包 interface 中的所有方法

7.常用的string函数 leetcode:151

返回 str 空格分隔的所有子串的 slice
strings.Fields(s string) []string 
sli := strings.Fields("I love beijing")
/*输出:[I love beijing]*/

用 sep 把 a 中的所有元素链接起来
strings.Join(a []string,sep string) string
str := strings.Join([]string{"I", "love", "beijing"}, "@")
/*输出:I@love@beijing*/

func Split(s, sep string) []string   //以sep分割

https://www.cnblogs.com/endurance9/p/10336372.html
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter02/02.1.html
常用的string函数https://learnku.com/articles/43150

还有一部分内容:
https://www.cnblogs.com/erenming/p/12072949.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值