golang学习笔记---数据类型
Go语言中有四种复合数据类型:数组,slice,map,结构体
数组和结构体都是聚合类型,长度固定。而slice和map都是动态数据结构,长度可变。
- 数组
var arrName [len]T
arrName := [...]int{1, 2, 3}
arrName是数组的名字,len是数组的长度,需要是常量,在编译时确定。T是数组元素的类型。
长度也可以通过初始化元素个数决定,这时,len部分使用"..."代替。
如果数组元素是可比较的,那么数组也是可比较的。但只能是同类型的数组才能比较,否则编译错误。
%t - 输出一个bool值,%T - 输出一个变量的类型。
****** 数组是按值传递的,但可以通过传递一个数组指针。
2.slice
表示一个拥有相同类型元素的可变长度序列:[]T,看上去像没有长度的数组类型。
slice有三个属性:指针,长度,容量, len, cap
一个底层数组可以对应多个slice,而且这些slice之间也可以重叠。
可以通过子串生成操作,从数组或者slice得到slice,访问容量外的元素,会导致宕机错误。
创建一个数组的slice,等于为数组创建了一个别名。
和数组不同,slice无法做比较,因此不能用 == , 在测试两个slice是否拥有相同的元素。标准库里面提供了高度优化的bytes.Equal来比较两个字节slice ([]byte),但对于其他类型,则需要我们自己写函数来比较。
slice只能与nil做比较,slice不能作为map的key。
对于可能修改slice属性的函数,一般都返回 修改后的slice,规则是:将函数返回值赋值给此前的slice。 xs = append(xs, y)
copy函数也很常用。
slice并不是纯引用类型,而是像下面这种聚合类型:
type IntSlice struct { ptr *int len, cap int }
对于下面的列子:
package main import ( "fmt" ) func modifySlice(s []int) { s[0] = 0 } func appendSlice(s []int) (s1 []int) { s1 = append(s, 4) return s1 } func main() { s := []int{1, 2, 3} fmt.Println(s) // [1,2,3] modifySlice(s) fmt.Println(s) // [0,2,3] appendSlice(s) fmt.Println(s) // [0,2,3] s = appendSlice(s) fmt.Println(s) // [0,2,3,4] }
输出:
[1 2 3] [0 2 3] [0 2 3] [0 2 3 4]
解说:
modifySlice(s) // [0,2,3], 虽然ptr是传值的,但其是指针,可以修改其所指地址的内容,当然这里要在len的范围内。
appendSlice(s) // [0,2,3], ptr,len, cap都是传值的,虽然在函数里面len发生了变化,ptr, cap是否发生变化不定,但当其返回这里时,ptr, len, cap都不可能变化,因此s没有变化
- map
GO语言中的map是散列表的引用,map[K]V,其中K类型,必须可以通过 == 进行比较,虽然浮点数也可以,但不是一个好主意。
可以用make来创建一个map:
ages := make( map[string]int )
或者
ages := map[string]int { "alice":31, "charlie":34, }
完整示例:
package main import ( "fmt" ) func main() { ages := map[string]int{ "alice": 31, "charlie": 34, //注意这里的逗号必须有 } fmt.Println(ages) }
package main import ( "fmt" ) func main() { ages := make(map[string]int) ages["tom"] = 19 ages["jimmy"] = 30 fmt.Println(ages) }
可以使用delete函数从map中删除一个元素。 delete(ages, "jimmy")
package main import ( "fmt" ) func main() { ages := make(map[string]int) ages["tom"] = 19 ages["jimmy"] = 30 fmt.Println(ages) delete(ages, "jimmy") fmt.Println(ages) }
输出:
map[jimmy:30 tom:19] map[tom:19]
但是map元素不是一个变量,不可以获取它的地址。因为map是动态变化的。
对于nil的map,可以查找,删除,获取元素个数,但是设置操作会导致错误。设置元素前,必须初始化map。
和slice一样,map也是不可比较的,唯一合法的就是和nil做比较。
map可以实现集合类型,map[T]bool
unicode.ReplacementChar 就是解析Unicode编码遇到不合法的UTF-8字符时,返回的值。
map值类型本身可以是复合类型:
map[string]map[string]bool
4.结构体
type Name struct { ID int Name string ManagerID int }
可以通过点号访问起成员,点号也适用于结构体指针,和C语言不一样,不需要 ->
结构体定义中不可以包含自己,但可以包含本身的指针,这样可以构造链表,树等结构。
没有任何成员的结构体称为空结构体,写作 struct {}。他没有长度,也不携带任何信息。
其成员是否可以导出,看其名字的首字母是否大写。
在Go这种按值调用的语言中,调用函数接收到的是实参的一个副本,并不是实参的引用。
Go允许我们定义不带名称的结构体成员,只需要制定类型即可;这种结构体成员称为匿名成员。这个结构体成员的类型必须是一个命名类型或者指向命名类型的指针。
package main import ( "fmt" ) type Point struct { X, Y int } type Circle struct { Point Radius int } func main() { var circle Circle circle.X = 5 circle.Y = 10 circle.Radius = 20 fmt.Println(circle) }
5.JSON
JavaScript对象表示法(JSON)是一种发送和接收格式化信息的标准。其它标准还有:XML,ASN.1,Google的ProtocolBuffer。
JSON基本类型:数字、布尔值、字符串。
基础类型可以通过JSON的数组和对象进行组合。
JSON数组是一个有序的元素序列,每个元素之间使用逗号分割,两边使用方括号括起来。 - 数组,slice
JSON对象是一个从字符串到值的映射,写成name:value对的序列,每个元素之间用逗号分割,两边使用花括号括起来。 - map,结构体
例子:
// This sample program demonstrates how to decode a JSON response // using the json package and NewDecoder function. package main import ( "encoding/json" "fmt" "log" "net/http" ) type ( // gResult maps to the result document received from the search. gResult struct { GsearchResultClass string `json:"GsearchResultClass"` UnescapedURL string `json:"unescapedUrl"` URL string `json:"url"` VisibleURL string `json:"visibleUrl"` CacheURL string `json:"cacheUrl"` Title string `json:"title"` TitleNoFormatting string `json:"titleNoFormatting"` Content string `json:"content"` } // gResponse contains the top level document. gResponse struct { ResponseData struct { Results []gResult `json:"results"` } `json:"responseData"` } ) func main() { uri := "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=8&q=golang" // Issue the search against Google. resp, err := http.Get(uri) if err != nil { log.Println("ERROR:", err) return } defer resp.Body.Close() // Decode the JSON response into our struct type. var gr gResponse err = json.NewDecoder(resp.Body).Decode(&gr) if err != nil { log.Println("ERROR:", err) return } fmt.Println(gr) // Marshal the struct type into a pretty print // version of the JSON document. pretty, err := json.MarshalIndent(gr, "", " ") if err != nil { log.Println("ERROR:", err) return } fmt.Println(string(pretty)) }