packagemainimport("fmt")//interface definitiontypeVowelsFinderinterface{FindVowels()[]rune// 必須回傳 []rune type}typeMyStringstring//MyString implements VowelsFinderfunc(msMyString)FindVowels()[]rune{varvowels[]runefor_,rune:=rangems{ifrune=='a'||rune=='e'||rune=='i'||rune=='o'||rune=='u'{vowels=append(vowels,rune)}}returnvowels}funcmain(){name:=MyString("Sam Anderson")varvVowelsFinder// 宣告 v 是 VowelsFinder interface typev=name// possible since MyString implements VowelsFinderfmt.Printf("Vowels are %c",v.FindVowels())}// Vowels are [a e o]
packagemainimport("fmt")typeSalaryCalculatorinterface{CalculateSalary()int//第一個是 method 名稱,第二個是 return type}// 長期雇工typePermanentstruct{empIdintbasicpayintpfint}// 合約雇工typeContractstruct{empIdintbasicpayint}// 長期雇工 實作 CalculateSalary()func(pPermanent)CalculateSalary()int{returnp.basicpay+p.pf}// 合約雇工實作 CalculateSalary()func(cContract)CalculateSalary()int{returnc.basicpay}/*total expense is calculated by iterating though the SalaryCalculator slice and summingthe salaries of the individual employees*/// 必須傳 slice 並且 type 是 SalaryCalculator interfacefunctotalExpense(s[]SalaryCalculator){expense:=0for_,v:=ranges{// v 必須都有實作 CalculateSalary()expense=expense+v.CalculateSalary()}fmt.Printf("Total Expense Per Month $%d",expense)}funcmain(){pemp1:=Permanent{1,5000,20}pemp2:=Permanent{2,6000,30}cemp1:=Contract{3,3000}employees:=[]SalaryCalculator{pemp1,pemp2,cemp1}totalExpense(employees)}// Total Expense Per Month $14050
packagemainimport("fmt")typeTestinterface{Tester()}typeMyFloatfloat64func(mMyFloat)Tester(){fmt.Println(m)}funcdescribe(tTest){fmt.Printf("Interface type %T value %v\n",t,t)}funcmain(){vartTestf:=MyFloat(89.7)t=f// 這裡將 type 是 MyFloat assign 給 type 是 Test interface 的 tdescribe(t)// 但印出 type 的時候會是原本底層具體的 type MyFloat 而不是 Testt.Tester()}// Interface type main.MyFloat value 89.7// 89.7
Empty Interface
interface{} 意味著任何型態的值,因為裡面沒有任何 method,也代表所有 type 都 implement
packagemainimport"fmt"funcprintAll(vals[]interface{}){//1for_,val:=rangevals{fmt.Println(val)}}funcmain(){names:=[]string{"stanley","david","oscar"}printAll(names)}// prog.go:14:10: cannot use names (type []string) as type []interface {} in argument to printAll
Type Assertion
Type assertion 可以用來取出 interface 底層的 value
12
i.(T)// used to get the underlying value of interface i whose concrete type is T.
123456789101112131415161718
packagemainimport("fmt")funcassert(iinterface{}){s:=i.(int)//get the underlying int value from i// 如果改成 string 則會 error// panic: interface conversion: interface {} is int, not stringfmt.Println(s)}funcmain(){varsinterface{}=56assert(s)}// 56
t, ok := i.(T) i 是 interface 類型的變數,T代表要斷言的類型,t 是 interface 變數存儲的值,ok 是 bool 類型表示是否為該斷言的類型 T
123456789101112131415161718
packagemainimport("fmt")funcassert(iinterface{}){v,ok:=i.(int)// 如果底層的 type 是 int,就會回傳 value & truefmt.Println(v,ok)}funcmain(){varsinterface{}=56assert(s)variinterface{}="Steven Paul"assert(i)}// 56 true// 0 false
Type Switch
當有多個或不確定的底層 type 時,可以用 switch 去做個別處理
1234567891011121314151617181920212223242526272829
packagemainimport("fmt")funcassert(iinterface{}){// Type Switchswitchv:=i.(type){caseint:fmt.Printf("Twice %v is %v\n",v,v*2)casestring:fmt.Printf("%q is %v bytes long\n",v,len(v))default:fmt.Printf("I don't know about type %T!\n",v)}}funcmain(){assert(21)assert("hello")assert(true)}/*Twice 21 is 42"hello" is 5 bytes longI don't know about type bool!*/
packagemainimport"fmt"typeDescriberinterface{Describe()}typePersonstruct{namestringageint}func(pPerson)Describe(){fmt.Printf("%s is %d years old",p.name,p.age)}funcfindType(iinterface{}){switchv:=i.(type){caseDescriber:// 這邊可以用 Describer or Personv.Describe()default:fmt.Printf("unknown type\n")}}funcmain(){findType("Naveen")p:=Person{name:"Naveen R",age:25,}findType(p)}/*unknown typeNaveen R is 25 years old*/
Implementing interfaces using pointer receivers vs value receivers
packagemainimport"fmt"typeDescriberinterface{Describe()}typePersonstruct{namestringageint}func(pPerson)Describe(){//implemented using value receiverfmt.Printf("%s is %d years old\n",p.name,p.age)}typeAddressstruct{statestringcountrystring}func(a*Address)Describe(){//implemented using pointer receiverfmt.Printf("State %s Country %s",a.state,a.country)}funcmain(){vard1Describer// 聲明 d1 是 Describer(interface) 類型p1:=Person{"Sam",25}d1=p1// 賦值 p1 到 d1d1.Describe()p2:=Person{"James",32}d1=&p2// 賦值 &p2 到 d1d1.Describe()vard2Describer// 聲明 d2 是 Describer(interface) 類型a:=Address{"Washington","USA"}//d2 = a// 當 assign value 時,必須要 implements interface 的內容,否則會 error// 原因在於 a 並沒有實作 Describe(),實作 Describe() 的是 pointer receiver,因此不能說 a 實作 Describer interface/* cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver) */d2=&a// 賦值 &a 到 d2d2.Describe()}/*Sam is 25 years oldJames is 32 years oldState Washington Country USA*/
packagemainimport("fmt")typeSalaryCalculatorinterface{DisplaySalary()}typeLeaveCalculatorinterface{CalculateLeavesLeft()int}typeEmployeestruct{firstNamestringlastNamestringbasicPayintpfinttotalLeavesintleavesTakenint}func(eEmployee)DisplaySalary(){fmt.Printf("%s %s has salary $%d",e.firstName,e.lastName,(e.basicPay+e.pf))}func(eEmployee)CalculateLeavesLeft()int{returne.totalLeaves-e.leavesTaken}funcmain(){e:=Employee{firstName:"Naveen",lastName:"Ramanathan",basicPay:5000,pf:200,totalLeaves:30,leavesTaken:5,}varsSalaryCalculator=es.DisplaySalary()varlLeaveCalculator=efmt.Println("\nLeaves left =",l.CalculateLeavesLeft())}// Naveen Ramanathan has salary $5200// Leaves left = 25
packagemainimport("fmt")typeSalaryCalculatorinterface{DisplaySalary()}typeLeaveCalculatorinterface{CalculateLeavesLeft()int}// 跟上面比較,多了一個這個typeEmployeeOperationsinterface{SalaryCalculatorLeaveCalculator}typeEmployeestruct{firstNamestringlastNamestringbasicPayintpfinttotalLeavesintleavesTakenint}func(eEmployee)DisplaySalary(){fmt.Printf("%s %s has salary $%d",e.firstName,e.lastName,(e.basicPay+e.pf))}func(eEmployee)CalculateLeavesLeft()int{returne.totalLeaves-e.leavesTaken}funcmain(){e:=Employee{firstName:"Naveen",lastName:"Ramanathan",basicPay:5000,pf:200,totalLeaves:30,leavesTaken:5,}varempOpEmployeeOperations=eempOp.DisplaySalary()fmt.Println("\nLeaves left =",empOp.CalculateLeavesLeft())}/*Naveen Ramanathan has salary $5200Leaves left = 25*/
// src/sort/sort.gopackagesort// A type, typically a collection, that satisfies sort.Interface can be// sorted by the routines in this package. The methods require that the// elements of the collection be enumerated by an integer index.// interface 是一個介面定義,用來讓第三方開發者定義自己的資料庫使用方式,就像一種規範。typeInterfaceinterface{// Len is the number of elements in the collection.Len()int// Less reports whether the element with// index i should sort before the element with index j.Less(i,jint)bool// Swap swaps the elements with indexes i and j.Swap(i,jint)}...// Sort sorts data.// It makes one call to data.Len to determine n, and O(n*log(n)) calls to// data.Less and data.Swap. The sort is not guaranteed to be stable.funcSort(dataInterface){// Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.n:=data.Len()maxDepth:=0fori:=n;i>0;i>>=1{maxDepth++}maxDepth*=2quickSort(data,0,n,maxDepth)}
packagemainimport("fmt""time")typeMyErrorstruct{Whentime.TimeWhatstring}func(e*MyError)Error()string{returnfmt.Sprintf("at %v, %s",e.When,e.What)}funcrun()error{return&MyError{time.Now(),"it didn't work",}}funcmain(){iferr:=run();err!=nil{fmt.Println(err)}}// at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't work
packagemainimport("io""os""strings")// 轉換 ROT13funcrot13(bbyte)byte{vara,zbyteswitch{// 判斷是小寫還是大寫的範圍case'a'<=b&&b<='z':a,z='a','z'case'A'<=b&&b<='Z':a,z='A','Z'// 特殊符號就直接回傳default:returnb}// a & b 會自動轉成 ASCII 碼數字return(b-a+13)%(z-a+1)+a}// 建立一個 rot13Reader 並且有 Read methodtyperot13Readerstruct{rrio.Reader}func(rrot13Reader)Read(p[]byte)(nint,errerror){// n 為 s 字串的長度n,err=r.rr.Read(p)fori:=0;i<n;i++{p[i]=rot13(p[i])}return}funcmain(){s:=strings.NewReader("Lbh penpxrq gur pbqr!")r:=rot13Reader{s}io.Copy(os.Stdout,&r)}// You cracked the code!
packagemainimport("fmt""net/http")typeStringstringfunc(sString)ServeHTTP(whttp.ResponseWriter,r*http.Request){fmt.Fprint(w,s)}typeStructstruct{GreetingstringPunctstringWhostring}func(s*Struct)ServeHTTP(whttp.ResponseWriter,r*http.Request){fmt.Fprint(w,s.Greeting,s.Punct,s.Who)}funcmain(){http.Handle("/string",String("I'm a frayed knot."))http.Handle("/struct",&Struct{"Hello",":","Gophers!"})http.ListenAndServe("localhost:4000",nil)}