方法
方法能给用户定义的类型添加新的行为,方法实际上也是函数
如果一个函数有接收者,这个函数被称为方法
//该示例展示如何声明并使用方法
package main
import(
"fmt"
)
//user 在程序里定义一个用户类型
type user struct {
name string
email string
}
//notify 使用值接收者实现了一个方法
func (u user) notify() {
fmt.Printf("Sending user Email to %s<%s>\n",
u.name,
u.email)
}
//changeEmail 使用指针接收者实现了一个方法
func (u *user) changeEmail(email string) {
u.email = email
}
//main 是程序的入口
func main() {
//user 类型的值可以用来调用
//使用该值接收者声明的方法
bill := user{"Bill","bill@eamil.com"}
bill.notify()
//指向user类型值得指针也可以用来调用
//使用值接收者声明得方法
lisa := &user{"Lisa","lisa@eaminl.com"}
lisa.notify()
//user 类型得值可用用来调用
//使用指针接收者声明得方法
bill.changeEmail("bill@newdomain.com")
bill.notify()
//指向user类型值得指针可以用来调用
//使用指针接收者声明得方法
lisa.changeEmail("lisa@newdomain.com")
lisa.notify()
}
类型的本质
内置类型
数值类型,字符串类型,布尔类型
将值传递给方法或函数时,应传递一个对应值的副本
引用类型
切片,映射,通道,接口,函数
结构类型
接口
多态是指代码可以根据类型的具体实现采取不同行为的能力
标准库
示例
//展示如何使用io.Reader和io.Writer接口
//简单版本的curl程序
package main
import (
"fmt"
"io"
"net/http"
"os"
)
//init在main函数之前调用
func int() {
if len(os.Args) != 2 {
fmt.Println("Usage: ./example2 <url>")
os.Exit(-1)
}
}
//main 应用程序的入口
func main() {
//从Web服务器得到响应
r,err := http.Get(os.Args[1])
if err != nil {
fmt.Println(err)
return
}
//从Body赋值到Stdout
io.Copy(os.Stdout,r.Body)
if err := r.Body.Close();err != nil {
fmt.Println(err)
}
}
//展示bytes.Buffer使用io.Copy函数
package main
import (
"bytes"
"fmt"
"io"
"os"
)
//main 应用程序的入口
func main() {
var b bytes.Buffer
//将字符串写入Buffer
b.Write([]byte("Hello"))
//使用Fprintf将字符串拼接到Buffer
fmt.Fprintf(&b,"World!")
//将Buffer的内容写入到Stdout
io.Copy(os.Stdout,&b)
}
实现
方法集
定义了接口的接受规则
//展示GO如何使用接口
package main
import(
"fmt"
)
//notifier定义了通知类行为的接口
type notifier interface {
notify()
}
//user 定义了一个用户类型
type user struct {
name string
email string
}
//notify 使用指针接收者实现的方法
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
//main 应用程序入口
func main() {
//创建一个user类型的值,并发送通知
u := user{"Bill","bill@email.com"}
// sendNotification(&u)
sendNotification(u)
// 报错:
// cannot use u (type user) as type notifier in argument to sendNotification:
// user does not implement notifier (notify method has pointer receiver)
// 不能将u(类型是user)作为sendNotification的参数类型notifier
// user类型并没有实现notifier(notifier方法使用指针接收者声明)
//
}
//sendNotification接受一个实现了notifier接口的值并发送通知
func sendNotification(n notifier) {
n.notify()
}
多态
//使用接口展示多态行为
package main
import (
"fmt"
)
//notifier 定义了通知类行为的接口
type notifier interface {
notify()
}
//user 定义了一个用户类型
type user struct {
name string
email string
}
//notify 使用指针接收者实现了notifier接口
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
//admin 定义了管理员
type admin struct {
name string
email string
}
//notify 使用指针接收者实现了notifier接口
func (a *admin) notify() {
fmt.Printf("Sending admin email to %s<%s>\n",
a.name,
a.email)
}
//main 是程序的主入口
func main() {
//创建一个user值并传给sendNotification
bill := user{"Bill","bill@email.com"}
sendNotification(& bill)
//创建一个admin值并传给sendNotification
lisa := admin{"Lisa","lisa@email.com"}
sendNotification(&lisa)
}
//sendNotification 接受一个实现了notifier接口的值并发送通知
func sendNotification(n notifier) {
n.notify()
}
嵌入类型
//展示将一个类型嵌入到另一个类型,以及内部类型和外部类型之间的关系
package main
import (
"fmt"
)
//user 在程序里定义一个用户类型
type user struct {
name string
email string
}
//notify 实现一个可以通过user类型值的指针调用方法
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
//admin,一个拥有权限的管理员用户
type admin struct {
user //嵌入类型
level string
}
//main 应用程序入口
func main() {
//创建一个admin用户
ad := admin{
user: user{
name: "john smith",
email: "john@yahoo.com",
},
level: "super",
}
//可以直接访问内部类型的方法
ad.user.notify()
//内部类型的方法也被提升到外部类型
ad.notify()
}
//motifier定义了通知类行为的接口
type notifier interface {
notify()
}
//user在程序里定义一个用户类型
type user struct {
name string
email string
}
//通过user类型值得指针调用方法
func (u *user) notify() {
fmt.Printf("Sending user mail to %s<%s>\n",
u.name,
u.email)
}
//admin代表一个拥有权限得管理员用户
type admin struct {
user
level string
}
//main是应用程序的入口
func main() {
//创建一个admin用户
ad := admin{
user: user{
name:"john smith",
email:"john@yahoo.com",},
level: "super",
}
//给admin用户发送一个通知
//用户实现接口内部类型的方法,被提升到外部类型
sendNotification(&ad)
}
//sendNotification接受一个实现notifier接口的值并发送通知
func sendNotification(n notifier) {
n.notify()
}
//展示内部类型和外部类型实现同一个接口时的做法
package main
import "fmt"
//notifier 定义了一个通知类行为的接口
type notifier interface {
notify()
}
//user 在程序里定义了一个用户类型
type user struct {
name string
email string
}
//通过user类型值的指针调用方法
func (u *user) notify() {
fmt.Printf("Sending user email to %s<%s>\n",
u.name,
u.email)
}
//admin 代表一个拥有权限的管理员用户
type admin struct {
user
level string
}
//通过admin类型值得指针调用得方法
func (a *admin) notify() {
fmt.Printf("Sending admin email to %s<%s>\n",
a.name,
a.email)
}
//main是应用程序得入口
func main() {
//创建一个admin用户
ad := admin{
user: user{
name: "john smith",
email: "john@yahoo.com",
},
level: "super",
}
//给admin用户发送一个通知
//接口得嵌入的内部类型实现并没有提升到外部类型
sendNotification(&ad)
//直接访问内部 类型的方法
ad.user.notify()
//内部类型的方法没有被提升
ad.notify()
}
//sendNotification接受一个实现了notifier接口的值并发送通知
func sendNotification(n notifier) {
n.notify()
}
公开或未公开的标识符
当一个标识符的名字以小写字母开头时,这个标识符就是未公开的,即包外的代码不可见
当一个标识符的名字以大写字母开头时,这个标识符就是公开的,即包外的代码可见
并发
并发与并行
并行:让不同的代码片段同时在不同的物理处理器上执行
goroutine
示例:
//创建连个goroutine,以并发的形式分别显示大写和小写的英文字母
//展示如何创建goroutine以及调度器的行为
package main
import (
"fmt"
"runtime"
"sync"
)
//main时程序的入口
func main() {
//分配一个逻辑处理器给调度器使用
runtime.GOMAXPROCS(1)
//wg用来等待程序完成
//计数器加2,表示要等待两个goroutine
var wg sync.WaitGroup
wg.Add(2)
//声明一个匿名函数,并创建一个goroutine
go func() {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
//显示字母表3次
for count := 0;count <3;count++ {
for char := 'a';char < 'a' + 26;char ++ {
fmt.Printf("%c",char)
}
fmt.Println("\n")
}
}()
//声明一个匿名函数,并创建一个goroutine
go func() {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
//显示字母表3次
for count := 0;count <3;count++ {
for char := 'A';char < 'A' + 26;char ++ {
fmt.Printf("%c",char)
}
fmt.Println("\n")
}
}()
//等待goroutine结束
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("\nTerminating Program")
}
//展示goroutine调度器在单个线程上切分时间片
package main
import (
"fmt"
"runtime"
"sync"
)
//wg用来等待程序完成
var wg sync.WaitGroup
//main是程序的入口
func main() {
//分配一个逻辑处理器给调度器使用
runtime.GOMAXPROCS(1)
//计数加2,表示要等待两个goroutine
wg.Add(2)
//创建两个goroutine
fmt.Print("Create Goroutines")
go printPrime("A")
go printPrime("B")
//等待goroutine结束
fmt.Println("Waiting To Finish")
wg.Wait()
fmt.Println("Terminating Program")
}
//printPrime 显示5000以内的素数值
func printPrime(prefix string) {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
next:
for outer := 2;outer < 5000; outer++ {
for inner := 2; inner < outer ; inner++ {
if outer%inner == 0{
continue next
}
}
fmt.Printf("%s:%d\n",prefix,outer)
}
fmt.Println("Completed",prefix)
}
竞争状态
如果两个或多个goroutine在灭有互相同步的情况下,访问某个共享资源,并试图同时读和写这个资源,久处于互相竞争的状态
//展示在程序中造成的竞争状态
//实际上不希望出现这种情况
//数据发生竞争
package main
import (
"fmt"
"runtime"
"sync"
)
var (
//counter 是所有goroutine都要增加其值的变量
counter int
//wg 用来等待程序结束
wg sync.WaitGroup
)
//main 是程序的入口
func main() {
//计数加2,表示要等待两个goroutine
wg.Add(2)
//创建两个goroutine
go incCounter(1)
go incCounter(2)
//等待goroutine结束
wg.Wait()
fmt.Println("Finel Counter:",counter)
}
//incCounter 增加包里counter变量的值
func incCounter(id int) {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
for count := 0 ;count < 2 ;count++ {
//捕获counter的值
value := counter
//当前goroutine从线程退出,并放回到队列
runtime.Gosched()
//增加本地value变量的值
value++
//将该值保存会counter
counter = value
}
}
锁住共享资源
原子和函数
示例:
//展示使用atomic包来提供对数值类型的安全访问
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
)
var (
//counter 是所有goroutine都要增加其值的变量
counter int64
//wg 用来等待程序结束
wg sync.WaitGroup
)
//main 是程序入口
func main() {
//计数加2,表示要等待两个goroutine
wg.Add(2)
//创建两个goroutine
go incCounter(1)
go incCounter(2)
//等待goroutine结束
wg.Wait()
//显示最终的值
fmt.Println("Final Counter:",counter)
}
//incCounter 增加包里counter变量的值
func incCounter(id int) {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
for count := 0;count < 2;count++ {
//安全的对counter加1
atomic.AddInt64(&counter,1)
//当前goroutine从线程退出,并放回到队列
runtime.Gosched()
}
}
//展示使用atomic包里Store和Load类函数
//来提供对数值类型的安全访问
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
var (
//shutdown 是通知这个在执行的goroutine停止工作的标志
shutdown int64
//wg 用来等待程序结束
wg sync.WaitGroup
)
//main 是程序的入口
func main() {
//计数加2,表示要等待两个线程
wg.Add(2)
//创建两个goroutine
go doWork("A")
go doWork("B")
//给定goroutine执行的时间
time.Sleep(1 * time.Second)
//该停止工作了,安全设置shutdown标志
fmt.Println("Shutdown Now")
atomic.StoreInt64(&shutdown,1)
//等待goroutine结束
wg.Wait()
}
//doWork 用来模拟执行工作的goroutine,
//检测之前的shutdown标志来决定是否该提前终止
func doWork(name string) {
//在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
for {
fmt.Printf("Done %s Work\n",name)
time.Sleep(250 * time.Millisecond)
//是否需要停止工作
if atomic.LoadInt64(&shutdown) == 1 {
fmt.Printf("Shuting %s Down\n",name)
break
}
}
}