Go语言中有丰富的数据类型,除了基本的整形、浮点型、布尔型、字符串外,还有切片、结构体、函数、map、通道(channel)等。
基本类型:
布尔类型:bool
整型:int8、byte、int16、int、uint、uintptr等。
浮点类型:float32、float64。
复数类型:complex64、complex128。
字符串:string。
字符类型:rune。
错误类型:error。
复合类型:
指针(pointer)
数组(array)
切片(slice)
字典(map)
通道(chan)
结构体(struct)
接口(interface)
整型分为以下两个大类。
按长度分为:int8()、int16、int32(rune)、int64。
还有对应的无符号整型:uint8(byte)、uint16、uint32、uint64。
uint8是byte型,int16对应C语言中的short型,int64对应C语言中的long型。
8位整型长度为1字节,16位整型长度为2字节,32位整型长度为3字节,64位整型长度为4字节。
浮点型用于表示包含小数点的数据。
Go语言支持两种浮点型数:float32和float64,长度分别为4字节和8字节。默认是float64。
float32的浮点数的最大范围约为3.4e38,可以使用常量定义:math.MaxFloat32。精通到小数点后7位。
float64的浮点数的最大范围约为1.8e308,可以使用常量定义:math.MaxFloat64。精通到小数点后15位。
打印浮点数时,可以使用fmt包配合动词“%f”。
代码如下:
package main
import(
"fmt"
"math"
)
func main(){
fmt.Println("%f\n",math.Pi)
fmt.Println("%.2f\n",math.Pi)
}
代码输出如下:
%f
3.141592653589793
%.2f
3.141592653589793
两个复数类型complex64、complex128。complex64类型带有float32实部和虚部。complex128类型带有float64实部和虚部。
复数表示的示例如下:
package main
import (
"fmt"
)
func main() {
var v1 complex64
v1 = 3.2 + 12i
v2 := 3.2 + 12i
v3 := complex(3.2, 12)
v := v2 + v3
fmt.Println(v1, v2, v3, v)
}
运行结果如下:
(3.2+12i) (3.2+12i) (3.2+12i) (6.4+24i)
代码如下:
package main
import (
"fmt"
)
func main() {
v2 := 3.2 + 12i
v3 := complex(3.2, 12)
v := v2 + v3
fmt.Println(v2, v3, v)
vr := real(v)
vi := imag(v)
fmt.Println(vr, vi)
}
运行结果如下:
(3.2+12i) (3.2+12i) (6.4+24i)
6.4 24
布尔型数据在Go语言中以bool类型进行声明,布尔型数据只有true(真)和false(假)两个值。
Go语言中不允许将整型强制转换为布尔型。关键字为bool,默认为false。
代码如下:
package main
import (
"fmt"
"os"
)
func main() {
var USER = os.Getenv("USER")
var b bool
b = (1 != 0)
u := ("user" == USER)
fmt.Println(u, b)
}
运行结果如下:
false true
所有字节默认使用UTF-8编码标识Unicode文本。
在Go语言中,字符串的值是不可变的。当创建一个字符串之后,无法再次修改这个字符串的内容。
代码如下:
package main
import (
"fmt"
)
func main() {
s := "aA你2"
fmt.Println("字符串长度:", len(s))
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
}
s = "你好,"
t := s
s += "世界。"
fmt.Println(s)
//s[0] = 'L' //cannot assign to s[0] (strings are immutable)
fmt.Println(t)
}
运行结果如下:
字符串长度: 6
97
65
228
189
160
50
你好,世界。
你好,
字符串的值为双引号中的内容,可以在Go语言的源码中直接添加非ASCII码字符。
转移符 | 含义 |
\r | 回车符(返回行首) |
\n | 换行符(直接跳到下一行的同列位置) |
\t | 制表符 |
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
在Go语言源码中使用转义符代码如下:
package main
import(
"fmt"
)
func main(){
fmt.Println("str := \"c:\\Go\\bin\\go.exe\"")
}
代码输出如下:
str := "c:\Go\bin\go.exe"
字符串实现基于UTF-8编码
定义多行字符串:
“`”叫反引号,在键盘上1键左边的键。如果需要在源码中嵌入一个多行字符串时,就必须使用反引号字符。
定义多行字符串代码如下:
package main
import(
"fmt"
)
func main(){
const str =`Hello
World
!
\r\n`
fmt.Println(str)
}
输出如下:
Hello
World
!
\r\n
代码如下:
package main
import (
"fmt"
)
func main() {
str1 := `苟利国家生死以\n
岂因祸福避趋之`
str2 := "今天天气\n真好"
fmt.Println(str1)
fmt.Println(str2)
}
运行结果如下:
苟利国家生死以\n
岂因祸福避趋之
今天天气
真好
连续字符串(除了截取字符串,还可以使用+符号连续字符串),代码如下:
package main
import (
"fmt"
)
func main() {
s := "abcd你"
fmt.Println(s[4:] + "好")
str := "你好," + "Go语言。"
fmt.Println(str)
}
运行结果如下:
你好
你好,Go语言。
在Go语言中,字符串是可以使用==和<等符号进行比较的,通过比较逐字节的编码如下:
package main
import (
"fmt"
)
func main() {
s := "你"
t := "好"
if s < t {
fmt.Println(s[0], t[0])
fmt.Println(s[1], t[1])
fmt.Println(s[2], t[2])
}
a := "a"
b := "b"
if a < b {
fmt.Println(a[0], "小于", b[0])
}
}
运行结果如下:
228 229
189 165
160 189
97 小于 98
字符串遍历:
字符串修改:
因为在Go语言中,字符串内容不能修改,也就不能用s[i]这种方式修改字符串中的UTF-8编码,如果确实要修改,那么可以将字符串的内容复制到另一个可写的变量中,然后再进行修改。一般使用[]byte或[]rune类型。
修改字符串中的字节(用[]byte)的代码如下:
package main
import (
"fmt"
)
func main() {
s := "Hello 世界!"
b := []byte(s)
b[5] = ','
fmt.Printf("%s\n", s)
fmt.Printf("%s\n", b)
}
运行结果如下:
Hello 世界!
Hello,世界!
修改字符串中的字符(用[]rune)的代码如下:
package main
import (
"fmt"
)
func main() {
s := "Hello 世界!"
r := []rune(s)
r[6] = '中'
r[7] = '国'
fmt.Println(s)
fmt.Println(string(r))
}
运行结果如下:
Hello 世界!
Hello 中国!
Go语言的字符有两种:
一种是uint8类型,或者叫byte型,代表了ASCII码的一个字符。
另一种是rune类型,代表一个UTF-8字符。当需要处理中文、日文或者其他复合字符时,则需要用天rune类型。rune类型实际是一个int32 。代码如下:
package main
import(
"fmt"
)
func main(){
var a byte ='a'
fmt.Printf("%d %T\n",a,a)
var b rune ='你'
fmt.Printf("%d %T\n",b,b)
}
输出如下:
97 uint8
20320 int32
'a'对应的ASCII编码是97,'你'对应的Unicode码就是20320 。使用fmt.Printf中的“%T”动词可以输出变量的实际类型。
strings包
1、包含判断
判断一个字符串是否有相应的某个子字符串是经常遇到的一种字符串操作,在Go语言中可以使用strings包中的两个方法判断。
①前后缀包含:HasPrefix这种方法,用于判断字符串的前缀是否包含指定的子符串。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
str := "This is an example of string"
fmt.Printf("Does the string \"%s\" have prefix %s? \n", str, "Th")
fmt.Printf("%t\n", strings.HasPrefix(str, "Th"))
fmt.Printf("Does the string \"%s\" have prefix %s? \n", str, "string")
fmt.Printf("%t\n", strings.HasPrefix(str, "string"))
fmt.Printf("Does the string \"%s\" have prefix %s? \n", str, "example")
fmt.Printf("%t\n", strings.HasPrefix(str, "example"))
}
运行结果如下:
Does the string "This is an example of string" have prefix Th?
true
Does the string "This is an example of string" have prefix string?
false
Does the string "This is an example of string" have prefix example?
false
②子字符串包含:Contains,可以判断一个字符串是否包含指定子字符串。ContainsAny能够匹配更广泛的内容,它可可匹配Unicode字符。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ContainsAny("team", "i"))
fmt.Println(strings.ContainsAny("failure", "a&o"))
fmt.Println(strings.ContainsAny("foo", ""))
fmt.Println(strings.ContainsAny("", "i"))
fmt.Println(strings.Contains("team", "i"))
fmt.Println(strings.Contains("failure", "a&o"))
fmt.Println(strings.Contains("foo", ""))
fmt.Println(strings.Contains("", "i"))
}
运行结果如下:
false
true
false
false
false
false
true
false
2、索引:Index可以返回指定字符串的第一个字符的索引值,如果不在存相应的字符串则返回-1。LastIndex表示返回字符串最后一个字符出现位置的索引,-1表示不包含特定字符串。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
str := "Hi, I'm Job, Hi."
fmt.Printf("The position of \"Job\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Job"))
fmt.Printf("The Position of the first instance of \"Hi\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Hi"))
fmt.Printf("The Position of the Last instance of \"Hi\" is: ")
fmt.Printf("%d\n", strings.LastIndex(str, "Hi"))
fmt.Printf("The Position of \"Tim\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Burger"))
}
运行结果如下:
The position of "Job" is: 8
The Position of the first instance of "Hi" is: 0
The Position of the Last instance of "Hi" is: 13
The Position of "Tim" is: -1
3、替换:
代码如下:
package main
import (
"strings"
)
func main() {
str := "你好世界,这个世界真好。"
new := "地球"
old := "世界"
n := 1
println(strings.Replace(str, old, new, n))
}
运行结果如下:
你好地球,这个世界真好。
strings.Replace(str,old,new,n)函数一共有4个参数,其中第一个为原字符串,第二个表示原字符串中需要被替换的子字符串,new是替换内容,n则表示匹配到第几个old,如果把n改为数字-1,则表示匹配所有。
4、统计
①出现频率
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
str := "Golang is cool, right?"
var manyO = "o"
fmt.Printf("%d\n", strings.Count(str, manyO))
fmt.Printf("%d\n", strings.Count(str, "oo"))
}
运行结果如下:
3
1
strings.Count(str,manyO)有两个参数,第一个参数是原字符串,第二个参数是指要统计的子字符串。
②字符数量
代码如下:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
str := "你好世界"
fmt.Printf("%d\n", len([]rune(str)))
fmt.Println(utf8.RuneCountInString(str))
}
运行结果如下:
4
4
5、大小写转换
ToLower将字符串中的Unicode字符全部转换为相应的小写字符。
strings.ToLower(s) string
ToUpper将字符串中的Unicode字符全部转换为相应的大写字符。
strings.ToUpper(s) string
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
var orig = "How are you?"
var lower string
var upper string
fmt.Printf("%s\n", orig)
lower = strings.ToLower(orig)
fmt.Printf("%s\n", lower)
upper = strings.ToUpper(orig)
fmt.Printf("%s\n", upper)
}
运行结果如下:
How are you?
how are you?
HOW ARE YOU?
6、修剪
字符串的修剪主要是去年一些不需要的字符。一般使用strings.Trim函数来修剪。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println("## Trim 函数的用法")
fmt.Printf("%q\n", strings.Trim(" !!! Golang !!! ", "! "))
fmt.Printf("%q\n", strings.Trim(" !!! Golang !!! ", " ! "))
fmt.Printf("%q\n", strings.Trim(" !!! Golang !!! ", "!"))
fmt.Println("## TrimLeft 函数的用法")
fmt.Printf("%q\n", strings.TrimLeft(" !!! Golang !!! ", "! "))
fmt.Printf("%q\n", strings.TrimLeft(" !!! Golang !!! ", " ! "))
fmt.Printf("%q\n", strings.TrimLeft(" !!! Golang !!! ", "!"))
fmt.Println("## TrimSpace 函数的用法")
fmt.Println(strings.TrimSpace(" \t\n这是\t一句话 \n\t\r\n"))
}
运行结果如下:
## Trim 函数的用法
"Golang"
"Golang"
" !!! Golang !!! "
## TrimLeft 函数的用法
"Golang !!! "
"Golang !!! "
" !!! Golang !!! "
## TrimSpace 函数的用法
这是 一句话
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.Trim("今天天气真好", "今"))
fmt.Printf("%q\n", strings.Trim("今天天气真好", "天"))
fmt.Printf("%q\n", strings.Trim("今天天气真好", "今天"))
}
运行结果如下:
"天天气真好"
"今天天气真好"
"气真好"
7、分割
Go语言的strings包中封装了分割函数strings.Split,函数返回的是一个切片(slice)。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a boy a girl a dog a cat", "a "))
fmt.Printf("%q\n", strings.Split("xyz ", ""))
}
运行结果如下:
["a" "b" "c"]
["" "boy " "girl " "dog " "cat"]
["x" "y" "z" " "]
8、插入字符
string.Join用于将元素类型为string的slice使用分隔符号拼接组成一个字符串。strings.Fields函数用于把字符串转换为字符串切片,然后通过range获得每个切片值,最后使用string.Join向字符串插入指定的字符。除些之外还可以使用字节缓冲bytes.Buffer连接字符串。
代码如下:
package main
import (
"fmt"
"strings"
)
func main() {
str := "The quick brown for jumps over the lazy dog 中文"
strSli := strings.Fields(str)
fmt.Printf("%s\n", strSli)
for _, val := range strSli {
fmt.Printf("%s ", val)
}
fmt.Println()
str2 := strings.Join(strSli, ";")
fmt.Printf("%s\n", str2)
}
运行结果如下:
[The quick brown for jumps over the lazy dog 中文]
The quick brown for jumps over the lazy dog 中文
The;quick;brown;for;jumps;over;the;lazy;dog;中文
strconv包
主要用于字符串与其他类型的转换。
Itoa是把十进制数转换为字符串
FormatFloat是将64位浮点型的数字转换为字符串,函数参数如下:
strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string
其中fmt表示格式(其值可以是'b'、'e'、'f'或'g'),prec表示精席,bitSize的值为32则表示float32,为64则表示float64 。
strconv.Atoi(s string)(i int, err error)将字符串转换为int型。
strconv.ParseFloat(s string, bitSize int)(f float64, err error)将字符串转换为float64型。
代码如下:
package main
import (
"fmt"
"strconv"
)
func main() {
orig := "233"
fmt.Printf("orig当前是%T类型,且操作系统是%位。\n", orig, strconv.IntSize)
num, err := strconv.Atoi(orig)
fmt.Printf("num当前是%T类型,且数值是%d。\n", num, num)
fmt.Printf("%s\n", err)
num += 5
newS := strconv.Itoa(num)
fmt.Printf("%s\n", newS)
}
运行结果如下:
orig当前是string类型,且操作系统是%!位(int=64)。
num当前是int类型,且数值是233。
%!s()
238
字符串格式化
格式化指令 | 含义 |
%% | %字面量 |
%b | 一个二进制整数,将一个整数格式化为二进制的表达方式 |
%c | 一个Unicode的字符 |
%d | 十进制数值 |
%o | 八进制数值 |
%x | 小写的十六进制数值 |
%X | 大写的十六进制数值 |
%U | 一个Unicode表示法表示的整型码值,默认是4个数字字符 |
%s | 输出以原生的UTF-8字节表示的字符,如果console不支持UTF-8编码,则地输出乱码 |
%t | 以true或者false的方式输出布尔值 |
%v | 使用默认格式输出值,或者如果方法存在,则使用类型的String()方法输出的自定义值 |
%T | 输出值的类型 |
在Go语言中单个字符可以使用单引号(')来创建,字符串支持切片操作,但是需要注意的是,如果字符串都是由ASCII字符组成的,那可以随便使用切片进行操作,但是如果字符串中包含其他非ASCII字符,直接使用切片获取想要的单个字符时应十分小心,因为对字符串直接使用切片时是通过字节进行索引的,但是非ASCII字符在内存中可能不是由一字节组成的。如果想对字符串中的字符依次访问,可以使用range 操作符。
包括 切片类型(slice)、字典类型(map)、通道类型(channel)、指针类型(pointer)、数组类型(array)、结构化类型(struct)、函数类型(function)、接口类型(interface)以及错误类型(error)。它们内部结构复杂,不仅需要申请内存,还需要初始化相关属性。
切片是一个拥有相同类型元素的可变长度的序列。切片的声明方式如下:
var name []T
其中,T代码切片元素类型,可以是整形、浮点型、布尔型、切片、map、函数等。
切片的元素使用“[]”进行访问,在方括号中提供切片的索引即可访问元素,索引的范围从0开始,且不超过切片的最大容量。
强制类型转换:
基本格式:type_name(expression)
代码如下:
package main
import (
"fmt"
)
func main() {
sum := 11
count := 3
mean := float32(sum) / float32(count)
mean2 := sum / count
fmt.Printf("mean 的值为:%f\n", mean)
fmt.Printf("mean2 的值为:%d\n", mean2)
}
运行结果如下:
mean 的值为:3.666667
mean2 的值为:3
类型别名:(自定义数据类型)
在Go语言中,用type关键字来定义数据类型。
在Go语言中一般是用type关键字结合struct结构类型来实现的。代码中引用成员变量的方法是用“结构变量名+.+成员变量名”的方式。
代码如下:
package main
import (
"fmt"
)
type (
字符串 string
)
func main() {
var b 字符串
b = "这是中文。"
fmt.Println(b)
a := "这也是中文。"
//fmt.Println(b + a)
//invalid operation: b + a (mismatched types 字符串 and string)
fmt.Println(string(b) + a)
}
运行结果如下:
这是中文。
这是中文。这也是中文。
继承:
代码如下:
package main
import (
"fmt"
)
type O struct {
h int
}
func (a *O) Get() int {
return a.h
}
func (a *O) Set(h int) {
a.h = h
}
type OO struct {
O
i int
}
func (a *OO) Get() int {
a.i++
return a.O.Get()
}
func main() {
oo := new(OO)
oo.Set(42)
fmt.Println(oo, oo.Get())
}
运行结果如下:
&{{42} 1} 42
有界无类
代码如下:
package main
import (
"fmt"
)
type Duck float32
func (Duck) Quack() string {
return "嘎"
}
type Goose Duck
type Quacker interface {
Quack() string
}
func main() {
var d Duck = 0.
var q Quacker
type Goose struct{ Duck }
g := Goose{d}
g.Quack()
q = g
fmt.Println(q.Quack())
}
运行结果如下:
嘎
排序:
代码如下:
package main
import (
"fmt"
"math"
"sort"
)
func main() {
is := sort.IntSlice{3, 1, 4, 1, 5, 9, 2, 6}
ss := sort.StringSlice{"士", "农", "工", "商"}
fs := sort.Float64Slice{math.Inf(-1), math.Inf(+1), math.NaN()}
sort.Sort(is)
sort.Sort(ss)
sort.Sort(fs)
fmt.Println(is, ss, fs)
}
运行结果如下:
[1 1 2 3 4 5 6 9] [农 商 士 工] [NaN -Inf +Inf]
代码如下:
package main
import (
"fmt"
"sort"
)
type Vec struct{ x, y float64 }
func (v Vec) lenlen() float64 {
return v.x*v.x + v.y*v.y
}
type VecSlice []Vec
func (v VecSlice) Len() int {
return len(v)
}
func (v VecSlice) Less(i, j int) bool {
return v[i].lenlen() < v[j].lenlen()
}
func (v VecSlice) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func main() {
v0 := Vec{0, 0}
v1 := Vec{1, 0}
v2 := Vec{1, 1}
vs := VecSlice{v1, v2, v0}
fmt.Println(vs)
sort.Sort(vs)
fmt.Println(vs)
}
运行结果如下:
[{1 0} {1 1} {0 0}]
[{0 0} {1 0} {1 1}]
代码如下:
package main
import (
"fmt"
"sort"
)
type Rev struct {
sort.Interface
}
func (r Rev) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
func main() {
a := []int{6, 7, 4, 2}
sort.Ints(a)
fmt.Println(a)
sort.Sort(Rev{sort.IntSlice(a)})
fmt.Println(a)
}
运行结果如下:
[2 4 6 7]
[7 6 4 2]
类型断言
代码如下:
package main
import (
"fmt"
)
type (
T0 []string
T00 []string
T1 struct{ a, b int }
T11 struct{ c, d int }
T2 func(int, float64) *T0
T22 func(int, float64) *[]string
)
var (
t interface{}
t0 T0
t1 T1
t2 T2
)
func main() {
t = t0
{
v, ok := t.(T0)
fmt.Println(v, ok)
}
{
v, ok := t.([]string)
fmt.Println(v, ok)
}
{
v, ok := t.(T00)
fmt.Println(v, ok)
}
t = t1
{
v, ok := t.(T1)
fmt.Println(v, ok)
}
{
v, ok := t.(T11)
fmt.Println(v, ok)
}
t = t2
{
v, ok := t.(T2)
fmt.Println(v, ok)
}
{
v, ok := t.(T22)
fmt.Println(v, ok)
}
}
运行结果如下:
[] true
[] false
[] false
{0 0} true
{0 0} false
true
false