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.