Interfaces and other types
Interface
Sequence这个例子,调用sort package中的方法,对于集合要实现sort的接口:Len(), Less(i,j int) bool 和 Swap(i,j int)。Sequence同时通过String()对集合内容进行格式化。
package sequence_test import ( "fmt" "sort" "testing" ) type Sequence []int func (s Sequence) Len() int { return len(s) } func (s Sequence) Less(i, j int) bool { return s[i] < s[j] } func (s Sequence) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s Sequence) Copy() Sequence { copy := make(Sequence, 0, len(s)) return append(copy, s...) } func (s Sequence) String() string { s = s.Copy() sort.Sort(s) str := "[" for i, elem := range s { if i > 0 { str += " " } str += fmt.Sprint(elem) } return str + "]" } func (s Sequence) Stringsprint() string { s = s.Copy() sort.Sort(s) return fmt.Sprint(s) } func (s Sequence) StringIntSlice() string { s = s.Copy() sort.IntSlice(s).Sort() return fmt.Sprint(s) } func TestSequence(t *testing.T) { var s Sequence = Sequence{100, 12, 83, 34, 59, 86} t.Logf("%#v", s) t.Log(s) t.Log(s.String()) t.Log(s.Stringsprint()) t.Log(s.StringIntSlice()) }
=== RUN TestSequence f:\GO\go_test\sequence\sequence_test.go:54: sequence_test.Sequence{100, 12, 83, 34, 59, 86} f:\GO\go_test\sequence\sequence_test.go:55: [12 34 59 83 86 100] f:\GO\go_test\sequence\sequence_test.go:56: [12 34 59 83 86 100] f:\GO\go_test\sequence\sequence_test.go:57: [12 34 59 83 86 100] f:\GO\go_test\sequence\sequence_test.go:58: [12 34 59 83 86 100] --- PASS: TestSequence (0.00s) PASS ok loop/sequence 1.996s
类型转换
String()接口通过 “for i, elem := range”方式实现,也可以像Stringsprint直接调用fmt.Sprint处理实现。
由于要通过sort.Sort(slice)实现排序, slice这里就是Sequence只要实现sort三个接口Less, Swap, Len就可以。通过IntSlice(s)将 Sequence 转化为 IntSlice类型,则不需要实现三个接口。
Sequence 和[]int类型转化,其实他们是一样的, 不会产生新值,如果从整形到浮点型需要创建一个新值。
Interface conversions and type assertions
Type Switch使用接口方式判断一个值的类型。
package conversion_test import ( "testing" ) type Stringer interface { String() string } type GoStringer struct{} func (p *GoStringer) String() string { return "Helloworld" } func Gettype() string { var value interface { } var s Stringer = &GoStringer{} value = s switch str := value.(type) { case string: return str case Stringer: return str.String() } return "?" } func TestConversion(t *testing.T) { t.Log(Gettype()) }
也可以判断其是否某一值
package check_test import "testing" func TestCheck(t *testing.T) { var value interface{} value = "123" value = 123 str, ok := value.(string) if ok { t.Logf("string value is %q\n", str) } else { t.Logf("value is not a string\n") } }
Generality
泛型, 通过泛型使得NewCTR并不依赖加密算法和具体的数据源格式。也就是基于抽象接口的编程。
type Block interface { BlockSize() int Encrypt(dst, src []byte) Decrypt(dst, src []byte) } type Stream interface { XORKeyStream(dst, src []byte) } // NewCTR returns a Stream that encrypts/decrypts using the given Block in // counter mode. The length of iv must be the same as the Block's block size. func NewCTR(block Block, iv []byte) Stream
Interfaces and methods 接口方法
以net/http库中接口为例。
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
下面通过顶一个counter类型记录网页访问,次数,也可以通过管道进行通知(这里直接过滤掉了),另外也可以通过http.HandlerFunc来指定收到http请求后的处理函数。
package http_test import ( "fmt" "net/http" "os" "testing" ) /* in net/http type handler interface { ServeHTTP(ResponseWriter, *Request) } */ type Counter struct { n int } type Chan chan *http.Request func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) { ctr.n++ fmt.Fprintf(w, "counter = %d\n", ctr.n) } func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) { ch <- req defer func() { <-ch }() fmt.Fprintf(w, "notification sent\n") } func ArgServer(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "%s", os.Args) } func TestCounter(t *testing.T) { ctr := new(Counter) http.Handle("/counter", ctr) ch := make(Chan, 1) http.Handle("/chan", ch) http.Handle("/args", http.HandlerFunc(ArgServer)) http.ListenAndServe(":8090", nil) }
可以看到由于http.Handle第二个参数是接口类型, 他是可以支持结构, 整型,函数类型,channel的。
The blank identifier
the blank identifier 类似占位符, 对于赋值操作类似unix中的/dev/null
主要用以以下场景:
- 多赋值场景
package blank_test import ( "os" "testing" ) func TestBlank(t *testing.T) { path := "/usr/local" if _, err := os.Stat(path); os.IsNotExist(err) { t.Logf("%s does not exist \n", path) } }
- 未使用的导入和变量,由于go定义的变量或引入包必须使用,可以通过“_”变量的使用的前期开发中可以不必删除开始还没有使用的变量或包,可使程序编译。
package unused_test import ( "io" "testing" "fmt" "log" "os" ) func TestUnused(t *testing.T) { var _ io.Reader var _ = fmt.Print var _ log.Logger fd, err := os.Open("test.go") if err != nil { t.Log(err) } _ = fd }
- 由于辅助作用导入
import _ "net/http/pprof"
- 接口检查
如果需要判断 json.RawMessage是否实现了json.Marshaler , 这样可以在编译阶段进行接口实现的检查
var _ json.Marshaler = (*RawMessage)(nil)
Embedding
使用组合而不是继承, 在struct和interface中可以实现组合。 接口只能内嵌接口类型。
与继承不同,组合嵌入一类型后内部类型的方法可以供外部类型调用,但是他们的接收方法是属于内部类型的。
// ReadWriter stores pointers to a Reader and a Writer. // It implements io.ReadWriter. type ReadWriter struct { *Reader // *bufio.Reader *Writer // *bufio.Writer }
func (rw *ReadWriter) Read(p []byte) (n int, err error) { return rw.reader.Read(p) }
ReadWriter中的Reader, 内嵌了io.Reader, Writer也同样内嵌了io.Writer
// Reader implements buffering for an io.Reader object. type Reader struct { buf []byte rd io.Reader // reader provided by the client r, w int // buf read and write positions err error lastByte int // last byte read for UnreadByte; -1 means invalid lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid } type Writer struct { err error buf []byte n int wr io.Writer }
通过组合模式进行定制化输出。
package embed_test import ( "fmt" "log" "os" "testing" ) type Job struct { Command string *log.Logger } func NewJob(command string, logger *log.Logger) *Job { return &Job{command, logger} } func (job *Job) Printf(format string, args ...interface{}) { job.Logger.Printf("%s: %s", job.Command, fmt.Sprintf(format, args...)) } func TestJob(t *testing.T) { job := NewJob("CreateJob", log.New(os.Stderr, "Job ", log.Ldate)) job.Println("TestJob") job.Printf("%s\n", "TestJob") }
参考及引用
Photo by Johannes Plenio from Pexels
https://golang.org/doc/effective_go
Comments are closed.