方法 方法能给用户定义的类型添加新的行为,方法实际上也是函数 如果一个函数有接收者,这个函数被称为方法 //该示例展示如何声明并使用方法 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","[email protected]"} bill.notify() //指向user类型值得指针也可以用来调用 //使用值接收者声明得方法 lisa := &user{"Lisa","[email protected]"} lisa.notify() //user 类型得值可用用来调用 //使用指针接收者声明得方法 bill.changeEmail("[email protected]") bill.notify() //指向user类型值得指针可以用来调用 //使用指针接收者声明得方法 lisa.changeEmail("[email protected]") 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","[email protected]"} // 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","[email protected]"} sendNotification(& bill) //创建一个admin值并传给sendNotification lisa := admin{"Lisa","[email protected]"} 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: "[email protected]", }, 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:"[email protected]",}, 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: "[email protected]", }, 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 } } }
Go语言实战--笔记2
猜你喜欢
转载自blog.csdn.net/liao__ran/article/details/114397270
今日推荐
周排行