字符串:string
var str string
str = "Hello Go"
ch := str[0] //'H'
//格式化输出
fmt.Printf("The length of \"%s\" is %d \n", str, len(str))
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
// 转义字符:\
\n
:换行符\r
:回车符\t
:tab 键\u
或 \U :Unicode 字符\\
:反斜杠自身虽然可以通过数组下标方式访问字符串中的字符,但是和数组不同,在 Go 语言中,字符串是一种不可变值类型,一旦初始化之后,它的内容不能被修改,比如看下面这个例子:
str := "Hello world"
str[0] = 'X' // 编译错误
编译器报错:cannot assign to str[0]
Go 语言中字符串默认是 UTF-8 编码的 Unicode 字符序列,所以可以包含非 ANSI 字符,比如「Hello, 学院君」可以出现在 Go 代码中。但需要注意的是,如果你的 Go 代码需要包含非 ANSI 字符,保存源文件时请注意编码格式必须选择 UTF-8。特别是在 Windows 下一般编辑器都默认存为本地编码,比如中国地区可能是 GBK 编码而不是 UTF-8,如果没注意这点在编译和运行时就会出现一些意料之外的情况。
字符串的编码转换是处理文本文档(比如 TXT、XML、HTML 等)时非常常见的需求,不过 Go 语言默认仅支持 UTF-8 和 Unicode 编码,对于其他编码,Go 语言标准库并没有内置的编码转换支持。不过,所幸的是我们可以很容易基于 iconv 库包装一个。这里有一个开源项目可供参考:https://github.com/qiniu/iconv。
str := "hello"
str = str + ", continue" // hello, continue
str += str //hellohello
string.Join()
s := strings.Join([2]string{"ajwlf","20"}, ",")
buffer.WriteString()
效率比较高
var buffer bytes.Buffer
buffer.WriteString("ajwlf");
buffer.WriteString(",");
buffer.WriteString("20");
fmt.Printf("%s", buffer.String()) //ajwlf,20
str = "hello, world"
str_1 := str[:5] // 获取索引5(不含)之前的子串
str_2 := str[7:] // 获取索引7(含)之后的子串
str_3 := str[0:5] // 获取从索引0(含)到索引5(不含)之间的子串
fmt.Println(str_1)
fmt.Println(str_2)
fmt.Println(str_3)
上述代码打印结果如下:
hello
world
hello
第一种方式:字节数组遍历
str := "Hello, 世界"
n := len(str)
for i := 0; i < n; i++ {
ch := str[i] // 依据下标取字符串中的字符,类型为byte
fmt.Println(i, ch)
}
这个例子的输出结果为:
0 72
1 101
2 108
3 108
4 111
5 44
6 32
7 228
8 184
9 150
10 231
11 149
12 140
可以看出,这个字符串长度为 13,尽管从直观上来说,这个字符串应该只有 9 个字符。这是因为每个中文字符在 UTF-8 中占 3 个字节,而不是 1 个字节。
第二种方式:Unicode遍历
str := "Hello, 世界"
for i, ch := range str {
fmt.Println(i, ch) // ch 的类型为 rune
}
这个时候,打印的就是 9 个字符了,以 Unicode 字符方式遍历时,每个字符的类型是 rune
(早期的 Go 语言用 int
类型表示 Unicode 字符),而不是 byte
。
len(str)
: 求长度
+ 或 fmt.Sprintf()
: 拼接字符串
strings.Split()
: 分割字符串
strings.Contains
() : 判断是否包含
strings.HasPrefix() 或 stings.HasSuffix()
前后缀判断
strings.Index() 或 strings.LastIndex()
字串出现的位置
strings.Join(a[] string, seq string)
join操作
数组是一组具有相同数据类型在内存中有序存储的数据集合
特点
- 长度固定,不能修改
- 赋值和函数传递过程是值复制,涉及到内存 cop
声明方式 : var name [size]varType
var arr= [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
var arr1 [6]int
arr:=[5]int{1,2,3,4,5}
//如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
var arr1 = [5]float32{1: 2.0, 3: 1323.0}
数组长度不确定的情况下:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
多维数组的声明方式: var var_name[size1][size2]....[sizeN] varType
a := [3][4] int{
{0, 1, 2, 3} , /* 第一行索引为 0 */
{4, 5, 6, 7} , /* 第二行索引为 1 */
{8, 9, 10, 11}, /* 第三行索引为 2 */
//注意:以上代码中倒数第二行的 } 必须要有逗号,因为最后一行的 } 不能单独一行,也可以写成这样:
}
go语言还支持创建元素数量不一致的多维数组
package main
import "fmt"
func main() {
// 创建空的二维数组
animals := [][]string{}
// 创建三一维数组,各数组长度不同
row1 := []string{"fish", "shark", "eel"}
row2 := []string{"bird"}
row3 := []string{"lizard", "salamander"}
// 使用 append() 函数将一维数组添加到二维数组中
animals = append(animals, row1)
animals = append(animals, row2)
animals = append(animals, row3)
// 循环输出
for i := range animals {
fmt.Printf("Row: %v\n", i)
fmt.Println(animals[i])
}
}
切片(slice)是一组具有相同数据类型在内存中有序存储的可扩容的数据集合
声明方式:
var 切片名 []数据类型
var slice []int //此时切片只是一个nil,还没有开辟空间。
make([]数据类型,长度)
var slice []int = make([]int, 10) //会开辟传入的大小的空间
我们可以通过len()
和cap()
函数来求取我们的slice的长度和容量(长度就是我们当前slice中存了多少了元素,而容量是slice最大可以容纳的元素数量。)
切片在截取的时候返回的新的切片是指向原来的切片的内存地址的。感觉类似于浅拷贝,改变截取后的切片的值也会同步的改变原切片的值。
func main() {
//切片的截取
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
//切片名[起始下标:结束下标:容量] 左闭右开 包含起始下标 不包含结束下标
//s := slice[2:7]
//fmt.Println(s)
//s:=slice[2:]
//fmt.Println(s)
//s:=slice[:5]
//fmt.Println(s)
s := slice[2:5:6] //实际容量=容量-起始下标
fmt.Println(s)
//fmt.Println(len(s))
//fmt.Println(cap(s))
s[0] = 333
//切片的截取 是将新的切片指向源切片的内存地址 修改一个会影响另外一个
fmt.Println(s)
fmt.Println(slice)
fmt.Println(unsafe.Sizeof(slice))
fmt.Println(unsafe.Sizeof(s))
}
遇到错误:append(s, 6) (value of type []int) is not used
s := append(s, 6) --> s = append(s, 6)
package main
import "fmt"
func main() {
s := []int{1, 2, 3, 4, 5}
s = append(s, 6)
s = append(s, 7, 8)
fmt.Printf("s: %v\n", s)
s2 := []int{3, 4, 5}
s3 := []int{6, 7, 8}
s3 = append(s2, s3...) //添加另外一个切片
fmt.Printf("s3: %v\n", s3)
}
out:
s: [1 2 3 4 5 6 7 8]
s3: [3 4 5 6 7 8]
func main() {
index := 1
s := []int{1, 2, 3, 4, 5}
s = append(s[:index], s[index+1:]...) //删除s[index]
fmt.Printf("s: %v\n", s)
}
//out: s: [1 3 4 5]
func main() {
s := []int{1, 2, 3, 4, 5}
s3 := []int{}
s4 := make([]int, 5)
copy(s3, s)
copy(s4, s)
fmt.Printf("s: %v\n", s)
fmt.Printf("s3: %v\n", s3)
fmt.Printf("s4: %v\n", s4)
}
/*
copy( destSlice, srcSlice []T) int
其中 srcSlice 为数据来源切片,destSlice 为复制的目标(也就是将 srcSlice 复制到 destSlice),目标切片必须分配过空间且足够承载复制的元素个数,并且来源和目标的类型必须一致,copy() 函数的返回值表示实际发生复制的元素个数。
*/
声明方式:var map_variable map[key_data_type]value_data_type
m1 := map[string]string{
"name": "zhangsan",
"age": "22",
}
fmt.Println(m1)
m2 := make(map[string]int) //m2 == empty map
var m3 map[string]int //m3 == nil
fmt.Print(m2, m3)
fmt.Print("遍历...\n")
for i, v := range m1 {
fmt.Println(i, v)
}
底层基于 Hash 实现,基于 Key-Value,无序的数据集合
函数类型、字典类型和切片类型不能作为 key,不支持的操作类型会导致 panic
检测值是否存在
name := m1["name"]
fmt.Println(name)
//可以返回一个ok值 判断我们的key是否正确
nema, ok := m1["nema"] //找不到这个键 就会返回false
fmt.Print(nema, ok)
//所以可以改进代码
if name, ok := m1["name"]; ok == true {
fmt.Println(name)
}
var m map[string]int
// nil 类型,添加和修改会导致 panicnil: len/map[key]/delete(m, key)
// 可以正常工作 go run –race
或者 go build - race
只要将数据存储在内存中都会为其分配内存地址。内存地址使用十六进数据表示。
内存为每一个字节分配一个 32 位或 64 位的编号(与 32 位或者 64 位处理器相关)。
可以使用运算符 & (取地址运算符)来获取数据的内存地址。
func main() {
a := 10
//取出变量a在内存的地址
//fmt.Println(&a)
var p *int = &a
//fmt.Println(p)
//fmt.Println(&a)
//通过指针间接修改变量的值
*p = 132
fmt.Println(a)
//const MAX int = 100
//fmt.Println(&MAX)//err 不可以获取常量的内存地址
}
func main() {
//定义指针 默认值为nil 指向内存地址编号为0的空间 内存地址0-255为系统占用 不允许用户读写操作
//var p *int = nil
//*p = 123 //err
//fmt.Println(*p)
//开辟数据类型大小的空间 返回值为指针类型
//new(数据类型)
var p *int
p = new(int)
*p = 123
fmt.Println(*p)
}