Go语言实战--笔记2

方法
方法能给用户定义的类型添加新的行为,方法实际上也是函数
如果一个函数有接收者,这个函数被称为方法
//该示例展示如何声明并使用方法
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
      }
   }
}

猜你喜欢

转载自blog.csdn.net/liao__ran/article/details/114397270