Skip to content

Commit be514aa

Browse files
committed
Add Makefile and add GOPL ch7
1 parent e3f8982 commit be514aa

File tree

4 files changed

+479
-161
lines changed

4 files changed

+479
-161
lines changed

Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
all:
2+
./build.sh
3+
build:
4+
./build.sh
5+
rejoin:
6+
./rejoin.sh

docs/gopl/ch7.md

+164-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,168 @@ This chapter discusses:
1414

1515
#### Concrete type and interface type *
1616

17-
All the types discussed so far are *concrete types*. A concrete type specifies the exact representation of its values and exposes the intrinsic operations of that representation, such as arithmetic for numbers, or indexing, `append`, and `range` for slices. A concrete type may also provide additional behaviors through its methods. When you have a value of a concrete type, you know exactly what it is and what you can do with it.
17+
All the types discussed so far are [**concrete types**](https://en.wikipedia.org/wiki/Class_(computer_programming)#Abstract_and_Concrete). A concrete type specifies the exact representation of its values and exposes the intrinsic operations of that representation, such as arithmetic for numbers, or indexing, `append`, and `range` for slices. A concrete type may also provide additional behaviors through its methods. When you have a value of a concrete type, you know exactly what it is and what you can do with it.
1818

19-
There is another kind of type in Go called an *interface type*. An interface is an *abstract type*. It doesn't expose the representation or internal structure of its values, or the set of basic operations they support; it reveals only some of their methods. When you have a value of an interface type, you know nothing about what it is; you know only what it can do, or more precisely, what behaviors are provided by its methods.
19+
There is another kind of type in Go called an **interface type**. An interface is an [**abstract type**](https://en.wikipedia.org/wiki/Abstract_type). It doesn't expose the representation or internal structure of its values, or the set of basic operations they support; it reveals only some of their methods. When you have a value of an interface type, you know nothing about what it is; you know only what it can do, or more precisely, what behaviors are provided by its methods.
20+
21+
#### The `io.Writer` interface *
22+
23+
This book has used two similar functions for string formatting:
24+
25+
* `fmt.Printf`, which writes the result to the standard output (a file)
26+
* `fmt.Sprintf`, which returns the result as a string
27+
28+
Thanks to interfaces, both of these functions are in effect wrappers around a third function, `fmt.Fprintf`, which is agnostic about what happens to the result it computes:
29+
30+
```go
31+
package fmt
32+
33+
func Fprintf(w io.Writer, format string, args ...interface{}) (int, error)
34+
35+
func Printf(format string, args ...interface{}) (int, error) {
36+
return Fprintf(os.Stdout, format, args...)
37+
}
38+
39+
func Sprintf(format string, args ...interface{}) string {
40+
var buf bytes.Buffer
41+
Fprintf(&buf, format, args...)
42+
return buf.String()
43+
}
44+
```
45+
46+
The `F` prefix of `Fprintf` stands for *file* and indicates that the formatted output should be written to the file provided as the first argument.
47+
48+
* In the `Printf` case, the argument, `os.Stdout`, is an [`*os.File`](https://golang.org/pkg/os/#File).
49+
* In the `Sprintf` case, the argument is not a file but superficially resembles one: `&buf` is a pointer to a memory buffer to which bytes can be written.
50+
51+
The first parameter of `Fprintf` is not a file either. It's an [`io.Writer`](https://golang.org/pkg/io/#Writer), which is an interface type with the following declaration:
52+
53+
<small>[go/src/io/io.go](https://github.com/golang/go/blob/master/src/io/io.go)</small>
54+
55+
```go
56+
package io
57+
58+
// Writer is the interface that wraps the basic Write method.
59+
//
60+
// Write writes len(p) bytes from p to the underlying data stream.
61+
// It returns the number of bytes written from p (0 <= n <= len(p))
62+
// and any error encountered that caused the write to stop early.
63+
// Write must return a non-nil error if it returns n < len(p).
64+
// Write must not modify the slice data, even temporarily.
65+
//
66+
// Implementations must not retain p.
67+
type Writer interface {
68+
Write(p []byte) (n int, err error)
69+
}
70+
```
71+
72+
The `io.Writer` interface defines the contract between `Fprintf` and its callers.
73+
74+
* The contract requires that the caller provide a value of a concrete type like `*os.File` or `*bytes.Buffer` that has a method called `Write` with the appropriate signature and behavior.
75+
* The contract guarantees that `Fprintf` will do its job given any value that satisfies the `io.Writer` interface.
76+
* `Fprintf` may not assume that it is writing to a file or to memory, only that it can call `Write`.
77+
78+
Because `fmt.Fprintf` assumes nothing about the representation of the value and relies only on the behaviors guaranteed by the `io.Writer` contract, we can safely pass a value of any concrete type that satisfies `io.Writer` as the first argument to `fmt.Fprintf`. This freedom to substitute one type for another that satisfies the same interface is called *substitutability*, and is a hallmark of object-oriented programming.
79+
80+
The following example uses a new type. The `Write` method of the `*ByteCounter` type below merely counts the bytes written to it before discarding them. (The conversion is required to make the types of `len(p)` and `*c` match in the `+=` assignment statement.)
81+
82+
<small>[gopl.io/ch7/bytecounter/main.go](https://github.com/shichao-an/gopl.io/blob/master/ch7/bytecounter/main.go)</small>
83+
84+
```go
85+
type ByteCounter int
86+
87+
func (c *ByteCounter) Write(p []byte) (int, error) {
88+
*c += ByteCounter(len(p)) // convert int to ByteCounter
89+
return len(p), nil
90+
}
91+
```
92+
93+
Since `*ByteCounter` satisfies the `io.Writer` contract, we can pass it to `Fprintf`; the `ByteCounter` correctly accumulates the length of the result.
94+
95+
```go
96+
var c ByteCounter
97+
c.Write([]byte("hello"))
98+
fmt.Println(c) // "5", = len("hello")
99+
100+
c = 0 // reset the counter
101+
var name = "Dolly"
102+
fmt.Fprintf(&c, "hello, %s", name)
103+
fmt.Println(c) // "12", = len("hello, Dolly")
104+
```
105+
106+
#### The `fmt.Stringer` interface *
107+
108+
Besides `io.Writer`, `fmt.Stringer` is another interface of great importance to the `fmt` package. `Fprintf` and `Fprintln` provide a way for types to control how their values are printed. For example:
109+
110+
* In [Section 2.5](ch2.md#type-declarations), we defined a `String` method for the `Celsius` type so that temperatures would print as "`100°C`.
111+
* In [Section 6.5](ch6.md#example-bit-vector-type), we equipped `*IntSet` with a `String` method so that sets would be rendered using traditional set notation like "`{1 2 3}`".
112+
113+
Declaring a `String` method makes a type satisfy `fmt.Stringer`, which is one of the most widely used interfaces of all:
114+
115+
<small>[go/src/fmt/print.go](https://github.com/golang/go/blob/master/src/fmt/print.go)</small>
116+
117+
```go
118+
package fmt
119+
120+
// The String method is used to print values passed
121+
// as an operand to any format that accepts a string
122+
// or to an unformatted printer such as Print.
123+
type Stringer interface {
124+
String() string
125+
}
126+
```
127+
128+
[Section 7.10](#type-assertions) will explain how the `fmt` package discovers which values satisfy this interface.
129+
130+
### Interface Types
131+
132+
An interface type specifies a set of methods that a concrete type must possess to be considered an instance of that interface.
133+
134+
The `io.Writer` type is one of the most widely used interfaces because it provides an abstraction of all the types to which bytes can be written, such as files, memory buffers, network connections, HTTP clients, archivers and hashers. The `io` package defines many other useful interfaces. A `Reader` represents any type from which you can read bytes, and a `Closer` is any value that you can close, such as a file or a network connection. (Notice the naming convention for many of Go's single-method interfaces.)
135+
136+
```go
137+
package io
138+
139+
type Reader interface {
140+
Read(p []byte) (n int, err error)
141+
}
142+
143+
type Closer interface {
144+
Close() error
145+
}
146+
```
147+
148+
The following are examples of new interface types as combinations of existing ones:
149+
150+
```go
151+
type ReadWriter interface {
152+
Reader
153+
Writer
154+
}
155+
156+
type ReadWriteCloser interface {
157+
Reader
158+
Writer
159+
Closer
160+
}
161+
```
162+
163+
The syntax used above, which resembles [struct embedding](ch4#struct-embedding-and-anonymous-fields), enables us to name another interface as a shorthand for writing out all of its methods. This is called *embedding* an interface. We could have written `io.ReadWriter` without embedding like this:
164+
165+
```go
166+
type ReadWriter interface {
167+
Read(p []byte) (n int, err error)
168+
Write(p []byte) (n int, err error)
169+
}
170+
```
171+
172+
We can even use a mixture of the two styles:
173+
174+
```go
175+
type ReadWriter interface {
176+
Read(p []byte) (n int, err error)
177+
Writer
178+
}
179+
```
180+
181+
All three declarations have the same effect. The order in which the methods appear is immaterial. All that matters is the set of methods.

0 commit comments

Comments
 (0)