Go的基本数据类型

这是 Go 学习笔记的第一篇,主要是 Go 基本数据类型的学习总结。
由于本人一直使用 PHP 语言进行开发,在学习 Go 的过程中发现有些知识点经常混淆,遂将 Go 与 PHP 做了比较(仅限于二者的基本数据类型)。
 
Go
PHP
基本数据类型
布尔型
数字类型:
  • 整型(int、unit)
  • 浮点型(float32、float64)
  • 其它:byte(类似unit8)、rune(类似int32)等
字符串类型
派生类型:
  • 指针类型(Pointer)
  • 数组类型(Array)
  • 结构类型(Struct)
  • 管道类型(Channel)
  • 函数类型(Function)
  • 切片类型(Slice)
  • 接口类型(Interface)
  • Map类型(Map)
4 种标量类型:
  • boolean(布尔型)
  • integer(整型)
  • float(浮点型,也称作 double)
  • string(字符串)
3 种复合类型:
  • array(数组)
  • object(对象)
  • callable(可调用)
2 种特殊类型:
  • resource(资源)
  • NULL(无类型)
字符串
字节编码
  • 字符串的字节默认使用 UTF-8 编码
  • 支持 Unicode 字符
  • 只支持 256 的字符集,需要在代码中显式指定字符编码 header("Content-Type: text/html;charset=utf-8"); 或修改php.ini中有关默认字符集的设置 default_charset = "utf-8" 
  • 不支持 Unicode 字符
字符串定义
  • 双引号(""):双引号中的转义字符会被替换
  • 反引号(``):反引号中原生字符串中的转义字符(如\n)会被原样输出
  • 单引号(''):单引号括起来的单个字符,需要格式化输出,%c,否则输出字符码数
  • 双引号(""):双引号中的转义字符会被替换,可以解析变量,即将变量包含在双引号中
  • 单引号(''):与Go的反引号类似,转义字符不会被转义,原样输出
字符串长度

 len() :获取的是每个字符的 UTF-8 编码的长度和,而不是直接的字符数量。

如 len("hello,世界") 的结果是 12 不是 8

 strlen() :与 Go 的  len() 类似,得到的是字符串所占的字节数

 utf8.RuneCountInString() :获取字符串的真正长度,上面的 utf8.RuneCountInString("hello,世界") 的结果是 8。

注:需import "unicode/utf8"

获取字符串的真正长度可以使用下面两个函数:
  •  mb_strlen() :需安装 mbstring 扩展
  •  iconv_strlen() :返回字符串的字符数统计,是整型
字符串拼接
运算符 + :
str := "hello, " +
"world"
  • 字符串之间用加号“+”拼接。如果换行,+ 要放到当前行的末尾,不能放到下一行的开头
  • 使用这种拼接方式,里面的字符串是不可变的,每次运算都会产生一个新的、临时的字符串,给 GC 带来额外的负担,所以性能比较差
运算符 . :
$str = "hello, " . "world";
// 也可以写成:
$str = "hello, " . "world";
  • 字符串之间用句点 “.”拼接,换行对句点的位置没有要求
fmt.Sprintf():
fmt.Sprintf("%d:%s", 2018, "年")
  • 内部使用 []byte 实现,不会产生临时的字符串
  • 内部逻辑复杂,还用到了interface,性能一般
strings.Join()
strings.Join([]string{"hello", "world"}, ", ")
  • Join会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入
  • 已有一个数组的情况下,这种拼接方式的效率很高,但如果没有,去构造这个数据的代价也不小。
bytes.Buffer——优先推荐
var buffer bytes.Buffer
buffer.WriteString("hello")
buffer.WriteString(", ")
buffer.WriteString("world")
 
fmt.Print(buffer.String())
  • 使用这种拼接方式,可以把字符串当成可变字符使用,对内存的增长也有优化
  • 如果能预估字符串的长度,还可以用 buffer.Grow() 接口来设置 capacity。
strings.Builder——推荐
var b1 strings.Builder
b1.WriteString("ABC")
b1.WriteString("DEF")
 
fmt.Print(b1.String())
  • 内部通过 slice 来保存和管理内容
  • 提供了 Grow() 来支持预定义容量,这样可以避免扩容而创建新的 slice
  • 非线程安全,性能上和 bytes.Buffer 相差无几
数组
声明数组
  • 数组元素必须类型唯一,要么都是字符串,要么都是数字类型。如果想让数组元素类型为任意类型,可以使用空接口interface{}作为类型,当使用值时必须先做一个类型判断。
  • 声明时需要确定长度,如果采用不定长数组的方式声明,在初始化时会自动确定好数组的长度。
① var arr [2]int //var 数组名称 [数组长度]数组元素类型
② var arr = [2]int{1,2} //var 数组名称 = [数组长度]数组元素类型{元素1,元素2,...}
③ var arr = [5]string{3: "ab", 4: "cd"} //指定索引位置
④ var arr = [...]int{1,2} //var 数组名称 = [...]数组元素类型{元素1,元素2,...},不定长数组声明方式
⑤ new():创建的是数组引针,eg.  var arr1 = new([5]int) 
  • 声明时不需要确定长度,且数组元素可以多类型混合
$arr  = ['a', 'b', 'c', 123];
 
如果是 Go,会报错:
# command-line-arguments
./arr.go:6:34: cannot use 123 (type int) as type string in array or slice literal
值传递和
引用传递
var arr1 = new([5]int)
arr := arr1
arr1[2] = 100
fmt.Println(arr1[2], arr[2])
 
var arr2 [5]int
newarr := arr2
arr2[2] = 100
fmt.Println(arr2[2], newarr[2])
程序输出:
100 100
100 0
new([5]int)创建的是数组指针,arr和arr1指向同一地址,故而修改arr1时arr同样也生效;
而newarr是由arr2值传递(拷贝),故而修改任何一个都不会改变另一个的值。
达到与左侧相同的效果,PHP 代码如下:
$arr1 = [5, 10, 0, 20, 25];
$arr = &$arr1; //引用传递
$newArr = $arr1; //值传递
$arr1[2] = 100;
echo $arr1[2], $arr[2];
echo $arr1[2], $newArr[2];
 
程序输出:
100 100
100 0
PHP中的引用传递使用 & 符号。
切片
定义
  • 切片是引用(对底层数组一个连续片段的引用),不需要占用额外的内存,比数组效率高
  • 一个切片未初始化前默认为nil,长度为0
  • 切片的长度可变,可以把切片看成一个长度可变的数组
PHP中没有切片这个概念,但是在数组函数中有个 array_slice() 函数,可以根据 offset 和 length 返回指定的数组中的一段序列。与 Go 的切片相似。
$input = array("a", "b", "c", "d", "e");
$output = array_slice($input, 0, 3);   // returns "a", "b", and "c"
声明
① 切分数组
var arr = [5]int{1,2,3,4,5} //数组
var s []type = arr[start:end:max] //切片(包含数组start到end-1之间的元素),end-start表示长度,max-start表示容量
② 初始化
var s = []int{2, 3, 5, 7, 11} //创建了一个长度为 5 的数组并且创建了一个相关切片。
③ 切片重组
var s []type = make([]type, len, cap) //len 是数组的长度也是切片的初始长度,cap是容量,可选参数
简写为slice := make([]type, len)
字典
定义
  • 一种元素对的无序集合,一组称为元素value,另一组为唯一键索引key
  • 未初始化 map 的值为 nil。map 是引用类型
  • map 可以动态增长,声明时不需要定义长度
PHP的关联数组类似于 Go 的 Map。
声明
var mapName map[keyType]valueType
② var mapName map[keyType]valueType{k1:v1, k2:v2, ...}
var mapName = make(map[keyType]valueType, cap) //cap是可选参数,表示容量
其实 Go 的基本数据类型的知识点以及它和 PHP 的区别绝不止上面列出的这些,对比新旧两种语言的差别意义也不是很大,但对我来说,通过梳理可以达到温故知新的目的。 

猜你喜欢

转载自www.cnblogs.com/sunshineliulu/p/11616495.html