Go語言中沒有“類”的改變,不支持類的“繼承”等面向對象概念鹦聪。Go語言中通過結構體的內(nèi)嵌再配合接口比面向對象更具有更高的擴展性和靈活性账阻。
自定義類型和類型別名
自定義類型:新類型,可以基于內(nèi)置的基本類型定義泽本,也可以通過stuct定義宰僧;
類型別名:只存在代碼編寫過程中,編碼編譯字后就不存在观挎,增加提高代碼可讀性琴儿;例如,byte
是unit8
的類型別名嘁捷,rune
是int32
的類型別名造成。
//自定義類型
// NewInt 是一個新類型,具有int的特性
type NewInt int
//類型別名
type MyInt = int
func main() {
var a NewInt
fmt.Println(a) //0
fmt.Printf("%T\n", a) //main.NewInt
var b MyInt
fmt.Println(b) //0
fmt.Printf("%T\n", b) //int
}
結構體
結構體struct
是一種自定義類型雄嚣,可以封裝多個基本數(shù)據(jù)類型晒屎。
結構體是值類型。
結構體在內(nèi)存中是連續(xù)在一塊的缓升。
結構體中字段大寫字母
開頭表示可公開訪問
鼓鲁,小寫字母
表示私有
(僅在定義當前結構體的包中可訪問)。
//創(chuàng)建新的類型需要用type關鍵字
type student struct {
name string
age int
gender string
hobby []string
}
func main() {
var stu = student{
name : "張三",
age : 20,
gender : "男",
hobby : []string{"籃球", "足球", "乒乓球"},
}
fmt.Println(stu) // {張三 20 男 [籃球 足球 乒乓球]}
//采用.屬性方式訪問
fmt.Println(stu.name)
fmt.Println(stu.age)
fmt.Println(stu.gender)
fmt.Println(stu.hobby)
//struct是值類型港谊,如果初始化沒有設置值骇吭,則屬性是默認值
var lisi = student{}
fmt.Println(lisi) //{ 0 []}
//使用new關鍵字進行聲明(實例化),得到結構體指針
var wangwu = new(student)
// (*wangwu).name
wangwu.name = "王五"
wangwu.age = 18
fmt.Println(wangwu) //&{王五 18 []}
//聲明(實例化)歧寺,得到結構體指針
var aaa = &student{}
fmt.Println(aaa) //&{ 0 []}
//初始化
//只用值的燥狰,需要所有屬性都要初始化
var bbb = student{
"bbb",
18,
"男",
[]string{"a", "b"},
}
fmt.Println(bbb) //{bbb 18 男 [a b]}
//初始化,得到結構體指針
//key-value格式斜筐,不需要所有的屬性都初始化
var ccc = &student{
name : "ccc",
age : 18,
}
fmt.Println(ccc) //&{ccc 18 []}
}
同樣類型的字段可以寫在一行
type student struct {
id int
name,city string
}
自己實現(xiàn)構造函數(shù)
//創(chuàng)建新的類型需要用type關鍵字
type student struct {
name string
age int
gender string
hobby []string
}
//實現(xiàn)一個構造函數(shù)龙致,習慣上new加類型名
func newStudent(name string, age int, gender string, hobby []string) *student {
return &student{
name: name,
age: age,
gender: gender,
hobby: hobby,
}
}
func main() {
hobby := []string{"a", "b"}
stu := newStudent("zhang", 18, "男", hobby)
fmt.Println(stu.name)
fmt.Println(stu.age)
fmt.Println(stu.gender)
fmt.Println(stu.hobby)
}
匿名結構體
var user struct{Name string; Age int}
user.Name = "張三"
user.Age = 18
fmt.Printf("%#v\n", user)
方法和接受者
Go語言中的方法method
是一種作用于特定類型變量的函數(shù)。這種特定類型變量叫做接受者(Receiver)
顷链,類似于其它語言中的this
或者self
目代。
函數(shù)
是誰都可以調(diào)用的。
方法
就是某個具體的類型才能調(diào)用的函數(shù)嗤练。
func (接受者變量 接受者類型) 方法名(參數(shù)列表) (返回參數(shù)){
函數(shù)體
}
其中:
- 接受者變量:參數(shù)變量名在命名時候榛了,官方建議使用接受者類型名的第一個小寫字母,而不是self潭苞、this
- 接受者類型:可以是指針類型和非指針類型忽冻,一般情況下都用指針類型;如果修改接受者中的值此疹,必須用指針類型;
使用指針類型的接受者場景
- 需要修改接受者中的值
- 接受者是拷貝代價比較大對象
- 保持一致性,如果有某個方法使用了指針接受者蝗碎,那么其他的方法也應該使用指針接受者
注意:
- 不能給系統(tǒng)類型添加方法
- 不能給別的包定義的類型添加方法
package main
import "fmt"
type student struct {
name string
age int
gender string
hobby []string
}
//非指針類型接受者
func (s student) methodTest() {
//非指針類型是不能改值
s.age = 20
fmt.Printf("學生的姓名是%s\n", s.name)
}
//指針類型接受者
func (s *student) methodTestUpdate() {
s.age = 20
fmt.Printf("學生的姓名是%s\n", s.name)
}
func main() {
s := student{
name: "aaa",
age: 18,
}
s.methodTest() //學生的姓名是aaa
// 不能改值
fmt.Printf("學生的年齡是%d\n", s.age) //學生的年齡是18
s2 := &student{
name: "bbb",
age: 18,
}
s2.methodTestUpdate() //學生的姓名是bbb
fmt.Printf("學生的年齡是%d\n", s2.age) //學生的年齡是20
}
匿名字段
沒有變量名湖笨,只有類型的字段
不推薦匿名字段的寫法
package main
import "fmt"
//匿名字段,每個類型只能用一次蹦骑,不建議寫
type student struct {
name string
string
int
}
func main() {
s := student{
name: "aaa",
string: "222",
}
fmt.Println(s.name)
fmt.Println(s.string)
fmt.Println(s.int)
}
結構體嵌套
package main
import "fmt"
type address struct {
province string
city string
}
type student struct {
name string
age int
addr address
}
func main() {
s := student{
name: "aaa",
age: 20,
addr : address{
province: "山東",
city: "煙臺",
},
}
fmt.Println(s) //{aaa 20 {山東 煙臺}}
fmt.Println(s.name) //aaa
fmt.Println(s.addr.province) //山東
fmt.Println(s.addr.city) //煙臺
}
嵌套匿名結構體
匿名字段支持簡寫慈省,可以不加類型名
匿名字段沖突時,需要加上類型名眠菇,不能省略
package main
import "fmt"
type address struct {
province string
city string
}
type email struct {
province string
test string
}
type other struct {
province string
tmp string
}
type student struct {
name string
age int
addr address
//匿名字段
email
other
}
func main() {
s := student{
name: "aaa",
age: 20,
addr : address{
province: "山東",
city: "煙臺",
},
email: email{
province: "1",
test: "2",
},
other: other{
province: "3",
tmp: "4",
},
}
fmt.Println(s) //{aaa 20 {山東 煙臺} {1 2} {3 4}}
fmt.Println(s.name) //aaa
fmt.Println(s.addr.province) //山東
fmt.Println(s.addr.city) //煙臺
//可省略類型名
fmt.Println(s.test) //2
//匿名字段沖突時边败,需要加上類型名,不能省略
// fmt.Println(s.province) //ambiguous selector s.province
fmt.Println(s.email.province) //1
}
結構體的“繼承”
利用結構體嵌套捎废、匿名字段笑窜,實現(xiàn)結構體的“繼承”
package main
import "fmt"
type person struct {
name string
}
func (p *person)dinner() {
fmt.Printf("%s 要吃飯!\n", p.name)
}
type student struct {
number int
*person
}
func (s *student)study() {
fmt.Printf("%s的學號是%d\n", s.name, s.number)
}
func main() {
stu := student {
number: 100,
person: &person{
name: "張三",
},
}
fmt.Println(stu.name)
fmt.Println(stu.number)
stu.study()
stu.dinner()
}
結構體與JSON序列化
序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串
反序列化:把JONS格式的字符串轉成編程語言中的對象
package main
import (
"fmt"
"encoding/json"
)
type Student struct {
Id int `json:"id"` //通過tag實現(xiàn)json序列化該字段時的key
Name string `json:"name"`
}
func main() {
stu1 := &Student{
Id: 1,
Name: "張三",
}
fmt.Println("序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串")
v, err := json.Marshal(stu1)
if err != nil {
fmt.Println("JSON格式化出錯登疗!")
fmt.Println(err)
return
}
fmt.Println(v) //[]byte
fmt.Println(string(v)) //把[]byte轉換成string
fmt.Printf("%#v\n", string(v)) //看真實的格式
fmt.Println("反序列化:把JONS格式的字符串轉成編程語言中的對象")
str := string(v)
// str := "{\"Id\":1,\"Name\":\"張三\"}"
var stu2 = &Student{}
json.Unmarshal([]byte(str), stu2)
fmt.Println(*stu2)
fmt.Printf("%T\n", stu2)
}
輸出結果是:
序列化:把編程語言里面的數(shù)據(jù)轉換成JSON格式的字符串
[123 34 105 100 34 58 49 44 34 110 97 109 101 34 58 34 229 188 160 228 184 137 34 125]
{"id":1,"name":"張三"}
"{\"id\":1,\"name\":\"張三\"}"
反序列化:把JONS格式的字符串轉成編程語言中的對象
{1 張三}
*main.Student
結構體tag
tag是結構體的元信息排截,可以在運行的時候通過反射的機制讀取出來。例如定義json序列化時的tag辐益。
type Student struct {
Id int `json:"id"` //通過tag實現(xiàn)json序列化該字段時的key
Name string `json:"name"`
}
小練習
小練習1:結構體+函數(shù)
package main
import (
"fmt"
"os"
)
//使用函數(shù)實現(xiàn)一個簡單的圖書管理系統(tǒng)
//每本書都有書名断傲、作者、價格智政、上架信息
//用戶可以在控制臺添加書籍认罩、修改書籍信息、打印所有的書籍列表续捂、退出操作
type book struct {
title string
author string
price float32
publish bool
}
//定義一個book指針的切片
// var bookList = make([]book, 0, 200)
var bookList = make([]*book, 0, 200)
// 獲取用戶輸入
func userInput() (title string, author string, price float32, publish bool){
fmt.Print("請輸入標題:")
fmt.Scanln(&title)
fmt.Print("請輸入作者:")
fmt.Scanln(&author)
fmt.Print("請輸入價格:")
fmt.Scanln(&price)
fmt.Print("請輸入出版信息[true|false]:")
fmt.Scanln(&publish)
return
}
// 添加書籍
func addBook(){
var (
title string
author string
price float32
publish bool
)
title, author, price, publish = userInput()
newBook := book{title, author, price, publish}
// bookList = append(bookList, newBook)
bookList = append(bookList, &newBook)
fmt.Println("添加書籍成功猜年!")
}
//修改書籍
func updateBook(){
var (
updateTitle string
existsFlag bool
title string
author string
price float32
publish bool
)
fmt.Print("請輸入要修改的原書籍名稱:")
fmt.Scanln(&updateTitle)
existsFlag = false
for _, bookInto := range bookList{
if bookInto.title == updateTitle {
existsFlag = true
}
}
if !existsFlag {
fmt.Println("書籍不存在!")
return
}
title, author, price, publish = userInput()
// newBook := book{title, author, price, publish}
// for index, bookInto := range bookList{
// if bookInto.title == updateTitle {
// bookList[index] = newBook
// fmt.Println("書籍修改成功疾忍!")
// }
// }
for _, bookInto := range bookList{
if bookInto.title == updateTitle {
p := bookInto
p.title = title
p.author = author
p.price = price
p.publish = publish
fmt.Println("書籍修改成功乔外!")
}
}
}
//展示書籍列表
func displayBook(){
if len(bookList) == 0 {
fmt.Println("無書籍!")
return
}
for index, bookInto := range bookList{
fmt.Printf("序號:%v\n", index+1)
fmt.Printf("標題:%s\n", bookInto.title)
fmt.Printf("作者:%s\n", bookInto.author)
fmt.Printf("價格:%0.2f\n", bookInto.price)
fmt.Printf("標題:%t\n", bookInto.publish)
}
}
func showMenu(){
fmt.Println("1. 添加書籍")
fmt.Println("2. 修改書籍信息")
fmt.Println("3. 展示所有書籍")
fmt.Println("4. 退出")
}
func main() {
for {
showMenu()
fmt.Print("請輸入操作序號:")
var opt string
fmt.Scanln(&opt)
switch opt {
case "1":
fmt.Println("--添加書籍操作--")
addBook()
fmt.Println("---------------")
case "2":
fmt.Println("--修改書籍操作--")
updateBook()
fmt.Println("---------------")
case "3":
fmt.Println("--展示書籍操作--")
displayBook()
fmt.Println("---------------")
case "4":
fmt.Println("--離開操作--")
os.Exit(0)
default :
fmt.Println("錯誤的操作選項一罩!")
fmt.Println("---------------")
}
}
}
小練習2:結構體+方法
package main
import (
"fmt"
"os"
)
//使用方法實現(xiàn)一個簡單的學生管理系統(tǒng)
//每本書都有學號杨幼、姓名、年齡聂渊、班級
//用戶可以在控制臺添加學生差购、修改學生、刪除學生汉嗽、展示學生列表欲逃、退出操作
type Student struct {
id int
name string
age int
class string
}
//構造函數(shù)
func NewStudent(id int, name string, age int, class string) *Student {
return &Student{
id: id,
name: name,
age: age,
class: class,
}
}
type StuMng struct {
stulist []*Student
}
func NewStuMng() *StuMng {
return &StuMng{
stulist: make([]*Student, 0, 100),
}
}
//添加學生
func (s *StuMng)addStudent(stu *Student) {
s.stulist = append(s.stulist, stu)
fmt.Println("添加學生成功!")
}
//判斷學號是否存在
func (s *StuMng)stuIdIsExists(id int) bool {
existsFlag := false
for _, value := range s.stulist {
if value.id == id {
existsFlag = true
}
}
return existsFlag
}
//修改學生
func (s *StuMng)updateStudent(stu *Student) {
if !s.stuIdIsExists(stu.id) {
fmt.Println("該學生學號不存在饼暑!")
return
}
for index, value := range s.stulist {
if value.id == stu.id {
s.stulist[index] = stu
}
}
fmt.Println("修改學生成功稳析!")
}
//刪除學生
func (s *StuMng)deleteStudent(id int) {
if !s.stuIdIsExists(id) {
fmt.Println("該學生學號不存在洗做!")
return
}
for index, value := range s.stulist {
if value.id == id {
s.stulist = append(s.stulist[:index], s.stulist[index+1:]...)
}
}
fmt.Println("刪除學生成功!")
}
//展示所有學生
func (s *StuMng)displayStudentList() {
if len(s.stulist) == 0 {
fmt.Println("無")
return
}
for _, stu := range s.stulist {
fmt.Printf("學號:%d彰居,姓名:%s诚纸,年齡:%d,班級:%s \n", stu.id, stu.name, stu.age, stu.class)
}
}
//操作菜單
func showMenuOpt(){
fmt.Println("1. 添加學生")
fmt.Println("2. 修改學生")
fmt.Println("3. 刪除學生")
fmt.Println("4. 展示所有學生")
fmt.Println("5. 退出")
}
// 獲取用戶輸入
func userInputContent() *Student{
var (
id int
name string
age int
class string
)
fmt.Print("請輸入學號:")
fmt.Scanln(&id)
fmt.Print("請輸入姓名:")
fmt.Scanln(&name)
fmt.Print("請輸入年齡:")
fmt.Scanln(&age)
fmt.Print("請輸入班級:")
fmt.Scanln(&class)
return NewStudent(id, name, age, class)
}
func main() {
sg := NewStuMng()
for {
showMenuOpt()
fmt.Print("請輸入操作序號:")
var opt string
fmt.Scanln(&opt)
switch opt {
case "1":
fmt.Println("--添加學生操作--")
stu := userInputContent()
sg.addStudent(stu)
fmt.Println("---------------")
case "2":
fmt.Println("--修改學生操作--")
stu := userInputContent()
sg.updateStudent(stu)
fmt.Println("---------------")
case "3":
fmt.Println("--刪除學生操作--")
var id int
fmt.Print("請輸入學號:")
fmt.Scanln(&id)
sg.deleteStudent(id)
fmt.Println("---------------")
case "4":
fmt.Println("--查詢所有學生操作--")
sg.displayStudentList()
fmt.Println("---------------")
case "5":
fmt.Println("--離開操作--")
os.Exit(0)
default :
fmt.Println("錯誤的操作選項陈惰!")
fmt.Println("---------------")
}
}
}