Go
1.聲明變量
1.指定變量類(lèi)型 (variable)
var i int
如果未指定默認(rèn)值 那么默認(rèn)值為0
2.自動(dòng)判斷值類(lèi)型
var i="string";
3.省略var 初始化聲明
hello:="spark"
多變量聲明
1.指定聲明變量的類(lèi)型 統(tǒng)一類(lèi)型
var i,k,s,w int
2.聲明不同的類(lèi)型
var (
i int
str string
b bool
)
!Q召庞!在同一個(gè)作用域當(dāng)中 不能對(duì)變量進(jìn)行二次初始化 :變量名=v
2.Go語(yǔ)言常量
const關(guān)鍵詞 常量聲明語(yǔ)法
1.單個(gè)常量聲明方法 顯示聲明 const 變量名 變量類(lèi)型=value
const str string ="100"
2.隱示聲明 可省略string 因?yàn)闀?huì)自動(dòng)推斷類(lèi)型
const str ="100"
const str,str1 int
3.枚舉聲明
const (
MAN=1
GIRL=0
)
4.特殊常量iota 在const關(guān)鍵詞出現(xiàn)時(shí)被重置為0 每次出現(xiàn)一次+1可以把iota當(dāng)作const索引
const (
MAN = iota //0
MAIN //1
_ //2
afer //3
)
3.運(yùn)算符
//算術(shù)運(yùn)算符
+ - * / ++ --
//關(guān)系運(yùn)算符 跟Java中的一致
== != > < >= <=
//邏輯運(yùn)算符
&& || !
4.for循環(huán)
//berak關(guān)鍵詞 停止當(dāng)前循環(huán)
//goto 跳轉(zhuǎn)到指定的標(biāo)簽
//continue 跳過(guò)當(dāng)前循環(huán)
func main() {
//var i="string";
for i:=1; i<=10 ;i++ {
// goto breakHader
if(i==1){
fmt.Println(i)
}else if(i==10){
fmt.Println("執(zhí)行")
goto breakHader
}else{
if(i==5){
fmt.Println(i)
break;
}
}
}
breakHader:
fmt.Print("Message")
}
5.Go函數(shù)
//聲明函數(shù)
func function_name(param list)(return paramList)
{
//函數(shù)體
}
//demo
func GetMaxNum(a ,b int)(int){
//聲明一個(gè)返回變量
var result int
if(a<b){
result=b;
}else if(b>a){
result=a
}
return result
}
//main函數(shù)
//noinspection ALL
func main() {
//var i="string";
var num=GetMaxNum(1,10);
fmt.Print(num)
}
//匿名函數(shù) 把一個(gè)函數(shù)作為方法的返回值
func function_name func()匿名函數(shù)返回值//int {
}
func getSequenes() func()int{
var i =0
return func() int{
i++
return i;
}
}
//noinspection ALL
func main() {
sequene := getSequenes()
fmt.Println(sequene())
fmt.Println(sequene())
//var i="string";
//var num=GetMaxNum(1,10);
//fmt.Print(num)
}
6.數(shù)組聲明
[length]Type
[N]Type{value1, value2, ..., valueN}
[...]Type{value1, value2, ..., valueN} 初始化數(shù)組
var 數(shù)組名稱(chēng)[] type
//不指定數(shù)組長(zhǎng)度
var 數(shù)組名稱(chēng)=[...]int{1,2,3,4,501}
-
語(yǔ)言指針
Go 語(yǔ)言的取地址符是 &,放到一個(gè)變量前使用就會(huì)返回相應(yīng)變量的內(nèi)存地址调塌。指針接受的是一個(gè)變量的內(nèi)存地址 如果直接賦值會(huì)報(bào)錯(cuò)
訪問(wèn)指針中的值 采用 *指針名稱(chēng)
一個(gè)指針變量指向了一個(gè)值的內(nèi)存地址滑燃。//輸出變量地址 var n [10]int /* n 是一個(gè)長(zhǎng)度為 10 的數(shù)組 */ n[0]=100 fmt.Printf("變量的地址: %x\n", &n[0] ) var a=10 //聲明指針變量 var i *int //存儲(chǔ) &a的地址 i=&a fmt.Printf("a 變量的地址是: %x\n", &a ) /* 指針變量的存儲(chǔ)地址 */ fmt.Printf("ip 變量?jī)?chǔ)存的指針地址: %x\n", i ) /* 使用指針訪問(wèn)值 */ fmt.Printf("*ip 變量的值: %d\n", *i )
8.結(jié)構(gòu)體定義
Go語(yǔ)言中的基礎(chǔ)數(shù)據(jù)類(lèi)型可以表示一些事務(wù)的基本熟悉次乓,但是當(dāng)我們想表達(dá)一個(gè)事務(wù)的全部或部分屬性時(shí),這時(shí)候使用單一基本數(shù)據(jù)類(lèi)型就無(wú)法滿足了。Go語(yǔ)言提供了一種自定義數(shù)據(jù)類(lèi)型陕贮,struct這種類(lèi)型稱(chēng)之為結(jié)構(gòu)體。我們可以采用struct來(lái)定義自己的類(lèi)型
//語(yǔ)法
type 類(lèi)型名 struct{
filedName type
filedName type
//1.類(lèi)型名 標(biāo)識(shí)自定義結(jié)構(gòu)體的名稱(chēng)封救,在同一個(gè)包內(nèi)不能重復(fù)
//2.字段名 表示結(jié)構(gòu)體字段名。結(jié)構(gòu)體中的字段名必須唯一
//3.字段類(lèi)型 表示結(jié)構(gòu)體字段的具體類(lèi)型
}
//比如 創(chuàng)建一個(gè)Person自定義類(lèi)型捣作,該類(lèi)型擁有name和age2個(gè)字段
type Person struct{
name string
age int
}
//結(jié)構(gòu)體實(shí)例化 結(jié)構(gòu)體本身也是一種類(lèi)型誉结,我們可以像聲明內(nèi)置類(lèi)型一樣使用var關(guān)鍵字聲明結(jié)構(gòu)體類(lèi)型
var 結(jié)構(gòu)體實(shí)例 結(jié)構(gòu)體類(lèi)型
//1.基本實(shí)例化
var person Person
person.name="zhangsan"
person.age=18
//2.匿名結(jié)構(gòu)體
var user struct{name string;age int}
user.name="李四"
user.age=20
//3. 創(chuàng)建指針類(lèi)型結(jié)構(gòu)體
//采用new關(guān)鍵字對(duì)結(jié)構(gòu)體進(jìn)行實(shí)例化,得到的是結(jié)構(gòu)體的地址
var p2=new(Person)
fmt.Println(p2)//&{ 0} 可以看出p2是一個(gè)結(jié)構(gòu)指針
//4.取結(jié)構(gòu)體的地址實(shí)例化 使用&對(duì)結(jié)構(gòu)體進(jìn)行取地址操作,相當(dāng)于對(duì)該結(jié)構(gòu)體類(lèi)型進(jìn)行了一次new實(shí)例化操作
var p2=&Person{}
p2.name="張三"
//p2.name="張三"其實(shí)在底層是(*p3).name="張三" 這是Go幫我們實(shí)現(xiàn)的語(yǔ)法糖
//5.使用鍵值對(duì)初始化 使用鍵值對(duì)對(duì)結(jié)構(gòu)體進(jìn)行初始化時(shí)券躁,鍵對(duì)應(yīng)結(jié)構(gòu)體的字段搓彻,值對(duì)應(yīng)字段的初始值
var p4=Person{name: "張三",age: 20}
fmt.Println(p4)//{張三 20}
//使用指針初始化
var p5=&Person{name: "張三",age: 21}
fmt.Println(p5)//&{張三 21}
//6使用值的列表進(jìn)行初始化
var p6= Person{"張三", 12}
//初始化結(jié)構(gòu)體的時(shí)候可以簡(jiǎn)寫(xiě),也就是初始化的時(shí)候不寫(xiě)鍵位嘱朽,直接寫(xiě)值
//使用該初始化操作的時(shí)候
//1.必須初始化結(jié)構(gòu)的所有字段
//2.初始值的填充順序必須與字段在結(jié)構(gòu)體內(nèi)的聲明順序一致
//3. 該方式不能和鍵值初始化方式混用
8.1 構(gòu)造函數(shù)
//Go語(yǔ)言的結(jié)構(gòu)體沒(méi)有構(gòu)造函數(shù)。所以我們可以自己實(shí)現(xiàn)怔接。如果結(jié)構(gòu)體比較復(fù)雜的話搪泳,值拷貝性能會(huì)比較大,所以構(gòu)造函數(shù)返回結(jié)構(gòu)的指針類(lèi)型 func NewPerson(name string, age int) *Person { return &Person{name, age} }
8.2 方法和接收者
Go語(yǔ)言中的方法是一種作用于特定類(lèi)型變量的函數(shù)扼脐。這種特定類(lèi)型變量叫做接收者(Reveiver)岸军。接收者的概念類(lèi)似于其他語(yǔ)言中的this或者self
func(接收者變量 接收者類(lèi)型)方法名(參數(shù)列表)(返回參數(shù)){ 1.接收者變量:接收者中的參數(shù)變量命名時(shí),官方建議使用接收者類(lèi)型名的第一個(gè)小寫(xiě)字母瓦侮。 2.接收者類(lèi)型: 接收者類(lèi)型和參數(shù)類(lèi)似艰赞,可以是指針類(lèi)型和非指針類(lèi)型 3.方法名、參數(shù)列表肚吏、返回參數(shù):具體格式與函數(shù)定義相同 } /Person 結(jié)構(gòu)體 type Person struct { name string age int8 } //NewPerson 構(gòu)造函數(shù) func NewPerson(name string, age int8) *Person { return &Person{ name: name, age: age, } } //Dream Person做夢(mèng)的方法 func (p Person) Dream() { fmt.Printf("%s的夢(mèng)想是學(xué)好Go語(yǔ)言方妖!\n", p.name) } func main() { p1 := NewPerson("測(cè)試", 25) p1.Dream() } //方法與函數(shù)的區(qū)別是 函數(shù)不屬于任何類(lèi)型,方法屬于特定的類(lèi)型 //方法的接收者類(lèi)型 可以是指針 也可以不是指針 唯一的區(qū)別如下 //Dream Person做夢(mèng)的方法 func (p Person) Dream() { p.name = "張三" } func (p *Person) Dreams() { p.name = "李四" } func main() { var p1 = new(Person) p1.name = "zs" p1.Dream() fmt.Println(p1) p1.Dreams() fmt.Println(p1) //輸出結(jié)果 變量接收者是結(jié)構(gòu)體變量的 無(wú)法改變接收者的值 // &{zs 0} //指針接收者可以修改接收者內(nèi)部的值 //&{李四 0} }
什么時(shí)候使用指針類(lèi)型?
- 需要修改接收者中的值
- 接收者是拷貝代價(jià)比較大的對(duì)象
- 保證一致性罚攀,如果有某個(gè)方法使用了指針接收者党觅,那么其他的方法也應(yīng)該使用指針接收者
8.3 結(jié)構(gòu)體的匿名字段
結(jié)構(gòu)體允許其成員字段在聲明時(shí)沒(méi)有字段名而只有類(lèi)型,這種沒(méi)有名字的字段就成為匿名字段
type Person struct{ string int } func main{ p:=Person{"zk",12} //匿名字段默認(rèn)采用類(lèi)型名作為字段名斋泄,結(jié)構(gòu)體要求字段必須唯一杯瞻,因此一個(gè)結(jié)構(gòu)體中同種類(lèi)型的匿名字段只能有一個(gè) }
8.4 嵌套結(jié)構(gòu)體
一個(gè)結(jié)構(gòu)體種可以嵌套包含另一個(gè)結(jié)構(gòu)體或結(jié)構(gòu)體指針
type Address struct{ Province string City string } type User struct{ Name string Address Address } func main(){ user1 := User{ Name: "張三", Address: Address{ Province: "浙江", City: "杭州", }, } fmt.Println(user1)//{張三 20 {浙江 杭州}} }
8.5 嵌套匿名結(jié)構(gòu)體
type Address struct{ Province string City string createTime string } type User struct{ Name string Gender string Address //匿名結(jié)構(gòu)體 Email } type Email struct{ Account string createTime string } func main() { user1 := User{ Name: "張三", Gender: "男", Address:Address{ Province: "浙江", City: "杭州", }, } fmt.Println(user1.City)//直接訪問(wèn)匿名結(jié)構(gòu)體的字段名 fmt.Println(user1.Province) //對(duì)于匿名結(jié)構(gòu)體內(nèi)部可能存在相同的字段名,這個(gè)時(shí)候 應(yīng)該為了避免歧義需要指定具體的內(nèi)嵌結(jié)構(gòu)體的字段 }
8.6 結(jié)構(gòu)體的"繼承"
Go語(yǔ)言中使用結(jié)構(gòu)體也就可以實(shí)現(xiàn)其他變成語(yǔ)言中面向?qū)ο蟮睦^承
type Animal struct { name string } func (a *Animal) move() { fmt.Println(a.name + "移動(dòng)") } type Dog struct { Feet int *Animal } func (d *Dog) wang() { fmt.Println(d.name + "WWWW") } func main() { //繼承 dog := Dog{Feet: 12, Animal: &Animal{name: "旺財(cái)"}} dog.move() dog.wang() }
8.7 結(jié)構(gòu)體字體地可見(jiàn)性
結(jié)構(gòu)體中字段大寫(xiě)開(kāi)頭表示可以公開(kāi)訪問(wèn)炫掐,小寫(xiě)表示私有(僅在定義當(dāng)前結(jié)構(gòu)體的包中可訪問(wèn))
8.9 結(jié)構(gòu)體與JSON序列化
JSON是一種輕量級(jí)的數(shù)據(jù)交換格式魁莉。易于人閱讀和編寫(xiě)。同時(shí)也易于機(jī)器解析和生成。JSON鍵值對(duì)是用來(lái)保存JS對(duì)象的一種方式旗唁,鍵/值對(duì)組合中的鍵名寫(xiě)在前面并用雙引號(hào)""包裹畦浓,使用冒號(hào)分隔,然后緊接著值逆皮;多個(gè)鍵值之間使用英文宅粥,分隔
type Student struct { No int //學(xué)號(hào) Name string //學(xué)生名稱(chēng) } type Class struct { ClassName string //班級(jí)名稱(chēng)你 Students []*Student } //如果有嵌套結(jié)構(gòu)體在內(nèi) 我們打印外層的結(jié)構(gòu)體可以正常輸出 可視化值,但是嵌套中的值輸出的都是一串地址 所以我們可以進(jìn)行重寫(xiě)對(duì)應(yīng)的結(jié)構(gòu)體的String方法 自定義輸出效果 func (c *Student) String() string { return "{Name:" + c.Name + " " + "No:" + strconv.Itoa(c.No) + "}" } func main() { class := &Class{ ClassName: "三年級(jí)二班", Students: make([]*Student, 0, 20)} for i := 0; i < 100; i++ { stu := &Student{ Name: fmt.Sprintf("stu%02d", i), No: i, } //追加 class.Students = append(class.Students, stu) } //序列化json data, _ := json.Marshal(class) fmt.Println(data) fmt.Printf("json:%s\n", data) //json.Marshal默認(rèn)返回的是一個(gè)byte結(jié)構(gòu) //[123 34 67 108 97 115 115 78 97 109 101 34 58 34 228 184 137 229 185 180....] //json:{"ClassName":"三年級(jí)二班","Students":[{"No":0,"Name":"stu00"},{"No":1,"Name":"stu01"},{"No":2,"Name":"stu02"},{"No":3,"Name":"stu03"},{"No":4,"Name":"stu04"},{"No":5,"Name":"stu05"}]} //json字符串轉(zhuǎn)換稱(chēng)json str := "{\"ClassName\":\"三年級(jí)二班\",\"Students\":[{\"No\":0,\"Name\":\"stu00\"},{\"No\":1,\"Name\":\"stu01\"},{\"No\":2,\"Name\":\"stu02\"},{\"No\":3,\"Name\":\"stu03\"},{\"No\":4,\"Name\":\"stu04\"},{\"No\":5,\"Name\":\"stu05\"},{\"No\":6,\"Name\":\"stu06\"}]}" //初始化Class c := &Class{} err := json.Unmarshal([]byte(str), c) if err == nil { fmt.Println(c) } }
8.10 結(jié)構(gòu)體標(biāo)簽(Tag)
Tag是結(jié)構(gòu)體的元信息电谣,可以在運(yùn)行的時(shí)候通過(guò)反射的機(jī)制讀取出來(lái)
Tag在機(jī)構(gòu)提字段的后方定義,由一對(duì)反引號(hào)包裹起來(lái),具體的格式如下:
`key:"value1" key2:"value2"`
結(jié)構(gòu)體標(biāo)簽由一個(gè)或多個(gè)鍵值對(duì)組成秽梅。鍵與值使用冒號(hào)分割,值用雙引號(hào)括起來(lái)剿牺。鍵值對(duì)之間使用一個(gè)空格分隔企垦。
type Student struct { Name string `json:"name"` Id int //json序列化默認(rèn)使用字段名作為key sex string //私有不能被json包訪問(wèn) } func main() { stu := &Student{Name: "張三", Id: 1, sex: "男"} json, _ := json.Marshal(stu) fmt.Println(string(json))//{"name":"張三","Id":1} }
8.11 map有序輸出
func main() { //創(chuàng)建一個(gè)int鍵值map數(shù)組 maps := make(map[int]string, 10) maps[1] = "A" maps[2] = "B" maps[3] = "C" maps[4] = "D" //創(chuàng)建一個(gè)存放maps的key值的數(shù)組 var sli []int //循環(huán)把所有的key放進(jìn)map當(dāng)中 for i, _ := range maps { sli = append(sli, i) } //排序 sort.Ints(sli) //循環(huán)輸出 for i := 0; i < len(maps); i++ { fmt.Println(maps[sli[i]]) } }
9.切片
Go 數(shù)組的長(zhǎng)度不可改變,在特定場(chǎng)景中這樣的集合就不太適用晒来,Go中提供了一種靈活钞诡,功能強(qiáng)悍的內(nèi)置類(lèi)型切片("動(dòng)態(tài)數(shù)組"),與數(shù)組相比切片的長(zhǎng)度是不固定的,可以追加元素湃崩,在追加時(shí)可能使切片的容量增大荧降。
切片是一種引用類(lèi)型
新獲得的切片跟源切片底層對(duì)應(yīng)的數(shù)組都是同一個(gè),所以對(duì)其中一個(gè)切片元素的修改也會(huì)影響到另外一個(gè)
聲明切片語(yǔ)法
make([]type, length, capacity)
make([]type, length)
[]type{}
[]type{value1, value2,..., valueN}
s[n] 切片s中索引位置為n的項(xiàng)
s[n:m] 從切片s的索引位置n到m-1處所獲得的切片
s[n:] 從切片s的索引位置到len(s)-1處所獲得的切片
s[:m] 從切片s的索引位置0到m-1處所獲得的切片
s[:] 從切片s的索引位置0到len(s)-1處獲得的切片
var identifier []type
切片初始化
s:=[]int{1,2,3}
/* 創(chuàng)建切片 長(zhǎng)度為4 最長(zhǎng)長(zhǎng)度可以達(dá)到4*/
slice := make([]int, 2, 4)
append_slice := []int{1, 2}
fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
//追加2個(gè)元素 地址未改變
slice = append(slice, append_slice...)
fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
//繼續(xù)追加 地址改變
slice = append(slice, 10, 20)
fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
slice = append(slice, 30, 40, 50)
fmt.Printf("slice addr:%p len:%d cap:%d slice:%v\n", slice, len(slice), cap(slice), slice)
slice addr:0xc000052140 len:2 cap:4 slice:[0 0]
slice addr:0xc000052140 len:4 cap:4 slice:[0 0 1 2]
slice addr:0xc00006c140 len:6 cap:8 slice:[0 0 1 2 10 20]
slice addr:0xc00008a000 len:9 cap:16 slice:[0 0 1 2 10 20 30 40 50]
10.創(chuàng)建Map集合
//聲明map的方式
var hashMap=make(map[keyType]valueType);
var hashMap=make(map[string]string)
hashMap["Lucy"]="張三"
hashMap["Ad"]="Nike"
for k, v := range hashMap {
fmt.Println(k+"\t"+v)
}
//刪除函數(shù)
delete(hashMap,"Lucy")
for k, v := range hashMap {
fmt.Println(k+"\t"+v)
}
11.類(lèi)型轉(zhuǎn)換
type_name(exp)
var name=12
var str=string(12)
//string轉(zhuǎn)int
nb,_=strconv.Atio(str)
//string轉(zhuǎn) int 64
in64, err := strconv.ParseInt(string, 10, 64)
//int轉(zhuǎn)換成string
string := strconv.Itoa(int)
//int64轉(zhuǎn)換成 string
string := strconv.FormatInt(int64,10)
12.接口定義 實(shí)現(xiàn)
demo
//定義一個(gè)say的接口
type Say interface {
sayHelloWorld();
}
type sayHello struct {
}
type saySpeak struct {
}
//實(shí)現(xiàn)類(lèi)
func (say sayHello) sayHelloWorld() {
fmt.Println("helloworld")
}
//實(shí)現(xiàn)類(lèi)
func ( saySpeak saySpeak)sayHelloWorld(){
fmt.Println("Nice")
}
func main() {
var say Say
say=new(sayHello)
say.sayHelloWorld();
say=new(saySpeak);
say.sayHelloWorld();
}
13 異常情況
package main
import (
"fmt"
)
// 定義一個(gè) DivideError 結(jié)構(gòu)
type DivideError struct {
dividee int
divider int
}
// 實(shí)現(xiàn) `error` 接口
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// 定義 `int` 類(lèi)型除法運(yùn)算的函數(shù)
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// 正常情況
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// 當(dāng)被除數(shù)為零的時(shí)候會(huì)返回錯(cuò)誤信息
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}