Text file
tour/methods.article
1 Methods and interfaces
2 This lesson covers methods and interfaces, the constructs that define objects and their behavior.
3
4 The Go Authors
5 https://golang.org
6
7 * Methods
8
9 Go does not have classes.
10 However, you can define methods on types.
11
12 A method is a function with a special _receiver_ argument.
13
14 The receiver appears in its own argument list between the `func` keyword and
15 the method name.
16
17 In this example, the `Abs` method has a receiver of type `Vertex` named `v`.
18
19 .play methods/methods.go
20
21 * Methods are functions
22
23 Remember: a method is just a function with a receiver argument.
24
25 Here's `Abs` written as a regular function with no change in functionality.
26
27 .play methods/methods-funcs.go
28
29 * Methods continued
30
31 You can declare a method on non-struct types, too.
32
33 In this example we see a numeric type `MyFloat` with an `Abs` method.
34
35 You can only declare a method with a receiver whose type is defined in the same
36 package as the method.
37 You cannot declare a method with a receiver whose type is defined in another
38 package (which includes the built-in types such as `int`).
39
40 .play methods/methods-continued.go
41
42 * Pointer receivers
43
44 You can declare methods with pointer receivers.
45
46 This means the receiver type has the literal syntax `*T` for some type `T`.
47 (Also, `T` cannot itself be a pointer such as `*int`.)
48
49 For example, the `Scale` method here is defined on `*Vertex`.
50
51 Methods with pointer receivers can modify the value to which the receiver
52 points (as `Scale` does here).
53 Since methods often need to modify their receiver, pointer receivers are more
54 common than value receivers.
55
56 Try removing the `*` from the declaration of the `Scale` function on line 16
57 and observe how the program's behavior changes.
58
59 With a value receiver, the `Scale` method operates on a copy of the original
60 `Vertex` value.
61 (This is the same behavior as for any other function argument.)
62 The `Scale` method must have a pointer receiver to change the `Vertex` value
63 declared in the `main` function.
64
65 .play methods/methods-pointers.go
66
67 * Pointers and functions
68
69 Here we see the `Abs` and `Scale` methods rewritten as functions.
70
71 Again, try removing the `*` from line 16.
72 Can you see why the behavior changes?
73 What else did you need to change for the example to compile?
74
75 (If you're not sure, continue to the next page.)
76
77 .play methods/methods-pointers-explained.go
78
79 * Methods and pointer indirection
80
81 Comparing the previous two programs, you might notice that
82 functions with a pointer argument must take a pointer:
83
84 var v Vertex
85 ScaleFunc(v, 5) // Compile error!
86 ScaleFunc(&v, 5) // OK
87
88 while methods with pointer receivers take either a value or a pointer as the
89 receiver when they are called:
90
91 var v Vertex
92 v.Scale(5) // OK
93 p := &v
94 p.Scale(10) // OK
95
96 For the statement `v.Scale(5)`, even though `v` is a value and not a pointer,
97 the method with the pointer receiver is called automatically.
98 That is, as a convenience, Go interprets the statement `v.Scale(5)` as
99 `(&v).Scale(5)` since the `Scale` method has a pointer receiver.
100
101 .play methods/indirection.go
102
103 * Methods and pointer indirection (2)
104
105 The equivalent thing happens in the reverse direction.
106
107 Functions that take a value argument must take a value of that specific type:
108
109 var v Vertex
110 fmt.Println(AbsFunc(v)) // OK
111 fmt.Println(AbsFunc(&v)) // Compile error!
112
113 while methods with value receivers take either a value or a pointer as the
114 receiver when they are called:
115
116 var v Vertex
117 fmt.Println(v.Abs()) // OK
118 p := &v
119 fmt.Println(p.Abs()) // OK
120
121 In this case, the method call `p.Abs()` is interpreted as `(*p).Abs()`.
122
123 .play methods/indirection-values.go
124
125 * Choosing a value or pointer receiver
126
127 There are two reasons to use a pointer receiver.
128
129 The first is so that the method can modify the value that its receiver points to.
130
131 The second is to avoid copying the value on each method call.
132 This can be more efficient if the receiver is a large struct, for example.
133
134 In this example, both `Scale` and `Abs` are methods with receiver type `*Vertex`,
135 even though the `Abs` method needn't modify its receiver.
136
137 In general, all methods on a given type should have either value or pointer
138 receivers, but not a mixture of both.
139 (We'll see why over the next few pages.)
140
141 .play methods/methods-with-pointer-receivers.go
142
143 * Interfaces
144
145 An _interface_type_ is defined as a set of method signatures.
146
147 A value of interface type can hold any value that implements those methods.
148
149 *Note:* There is an error in the example code on line 22.
150 `Vertex` (the value type) doesn't implement `Abser` because
151 the `Abs` method is defined only on `*Vertex` (the pointer type).
152
153 .play methods/interfaces.go
154
155 * Interfaces are implemented implicitly
156
157 A type implements an interface by implementing its methods.
158 There is no explicit declaration of intent, no "implements" keyword.
159
160 Implicit interfaces decouple the definition of an interface from its
161 implementation, which could then appear in any package without prearrangement.
162
163 .play methods/interfaces-are-satisfied-implicitly.go
164
165 * Interface values
166
167 Under the hood, interface values can be thought of as a tuple of a value and a
168 concrete type:
169
170 (value, type)
171
172 An interface value holds a value of a specific underlying concrete type.
173
174 Calling a method on an interface value executes the method of the same name on
175 its underlying type.
176
177 .play methods/interface-values.go
178
179 * Interface values with nil underlying values
180
181 If the concrete value inside the interface itself is nil,
182 the method will be called with a nil receiver.
183
184 In some languages this would trigger a null pointer exception,
185 but in Go it is common to write methods that gracefully handle being called
186 with a nil receiver (as with the method `M` in this example.)
187
188 Note that an interface value that holds a nil concrete value is itself non-nil.
189
190 .play methods/interface-values-with-nil.go
191
192 * Nil interface values
193
194 A nil interface value holds neither value nor concrete type.
195
196 Calling a method on a nil interface is a run-time error because there is no
197 type inside the interface tuple to indicate which _concrete_ method to call.
198
199 .play methods/nil-interface-values.go
200
201 * The empty interface
202
203 The interface type that specifies zero methods is known as the _empty_interface_:
204
205 interface{}
206
207 An empty interface may hold values of any type.
208 (Every type implements at least zero methods.)
209
210 Empty interfaces are used by code that handles values of unknown type.
211 For example, `fmt.Print` takes any number of arguments of type `interface{}`.
212
213 .play methods/empty-interface.go
214
215 * Type assertions
216
217 A _type_assertion_ provides access to an interface value's underlying concrete value.
218
219 t := i.(T)
220
221 This statement asserts that the interface value `i` holds the concrete type `T`
222 and assigns the underlying `T` value to the variable `t`.
223
224 If `i` does not hold a `T`, the statement will trigger a panic.
225
226 To _test_ whether an interface value holds a specific type,
227 a type assertion can return two values: the underlying value
228 and a boolean value that reports whether the assertion succeeded.
229
230 t, ok := i.(T)
231
232 If `i` holds a `T`, then `t` will be the underlying value and `ok` will be true.
233
234 If not, `ok` will be false and `t` will be the zero value of type `T`,
235 and no panic occurs.
236
237 Note the similarity between this syntax and that of reading from a map.
238
239 .play methods/type-assertions.go
240
241 * Type switches
242
243 A _type_switch_ is a construct that permits several type assertions in series.
244
245 A type switch is like a regular switch statement, but the cases in a type
246 switch specify types (not values), and those values are compared against
247 the type of the value held by the given interface value.
248
249 switch v := i.(type) {
250 case T:
251 // here v has type T
252 case S:
253 // here v has type S
254 default:
255 // no match; here v has the same type as i
256 }
257
258 The declaration in a type switch has the same syntax as a type assertion `i.(T)`,
259 but the specific type `T` is replaced with the keyword `type`.
260
261 This switch statement tests whether the interface value `i`
262 holds a value of type `T` or `S`.
263 In each of the `T` and `S` cases, the variable `v` will be of type
264 `T` or `S` respectively and hold the value held by `i`.
265 In the default case (where there is no match), the variable `v` is
266 of the same interface type and value as `i`.
267
268 .play methods/type-switches.go
269
270 * Stringers
271
272 One of the most ubiquitous interfaces is [[/pkg/fmt/#Stringer][`Stringer`]] defined by the [[/pkg/fmt/][`fmt`]] package.
273
274 type Stringer interface {
275 String() string
276 }
277
278 A `Stringer` is a type that can describe itself as a string. The `fmt` package
279 (and many others) look for this interface to print values.
280
281 .play methods/stringer.go
282
283 * Exercise: Stringers
284
285 Make the `IPAddr` type implement `fmt.Stringer` to print the address as
286 a dotted quad.
287
288 For instance, `IPAddr{1,`2,`3,`4}` should print as `"1.2.3.4"`.
289
290 .play methods/exercise-stringer.go
291
292 * Errors
293
294 Go programs express error state with `error` values.
295
296 The `error` type is a built-in interface similar to `fmt.Stringer`:
297
298 type error interface {
299 Error() string
300 }
301
302 (As with `fmt.Stringer`, the `fmt` package looks for the `error` interface when
303 printing values.)
304
305 Functions often return an `error` value, and calling code should handle errors
306 by testing whether the error equals `nil`.
307
308 i, err := strconv.Atoi("42")
309 if err != nil {
310 fmt.Printf("couldn't convert number: %v\n", err)
311 return
312 }
313 fmt.Println("Converted integer:", i)
314
315 A nil `error` denotes success; a non-nil `error` denotes failure.
316
317 .play methods/errors.go
318
319 * Exercise: Errors
320
321 Copy your `Sqrt` function from the [[/tour/flowcontrol/8][earlier exercise]] and modify it to return an `error` value.
322
323 `Sqrt` should return a non-nil error value when given a negative number, as it doesn't support complex numbers.
324
325 Create a new type
326
327 type ErrNegativeSqrt float64
328
329 and make it an `error` by giving it a
330
331 func (e ErrNegativeSqrt) Error() string
332
333 method such that `ErrNegativeSqrt(-2).Error()` returns `"cannot`Sqrt`negative`number:`-2"`.
334
335 *Note:* A call to `fmt.Sprint(e)` inside the `Error` method will send the program into an infinite loop. You can avoid this by converting `e` first: `fmt.Sprint(float64(e))`. Why?
336
337 Change your `Sqrt` function to return an `ErrNegativeSqrt` value when given a negative number.
338
339 .play methods/exercise-errors.go
340
341 * Readers
342
343 The `io` package specifies the `io.Reader` interface,
344 which represents the read end of a stream of data.
345
346 The Go standard library contains [[https://cs.opensource.google/search?q=Read%5C(%5Cw%2B%5Cs%5C%5B%5C%5Dbyte%5C)&ss=go%2Fgo][many implementations]] of this interface, including files, network connections, compressors, ciphers, and others.
347
348 The `io.Reader` interface has a `Read` method:
349
350 func (T) Read(b []byte) (n int, err error)
351
352 `Read` populates the given byte slice with data and returns the number of bytes
353 populated and an error value. It returns an `io.EOF` error when the stream
354 ends.
355
356 The example code creates a
357 [[/pkg/strings/#Reader][`strings.Reader`]]
358 and consumes its output 8 bytes at a time.
359
360 .play methods/reader.go
361
362 * Exercise: Readers
363
364 Implement a `Reader` type that emits an infinite stream of the ASCII character
365 `'A'`.
366
367 .play methods/exercise-reader.go
368
369 * Exercise: rot13Reader
370
371 A common pattern is an [[/pkg/io/#Reader][io.Reader]] that wraps another `io.Reader`, modifying the stream in some way.
372
373 For example, the [[/pkg/compress/gzip/#NewReader][gzip.NewReader]] function takes an `io.Reader` (a stream of compressed data) and returns a `*gzip.Reader` that also implements `io.Reader` (a stream of the decompressed data).
374
375 Implement a `rot13Reader` that implements `io.Reader` and reads from an `io.Reader`, modifying the stream by applying the [[https://en.wikipedia.org/wiki/ROT13][rot13]] substitution cipher to all alphabetical characters.
376
377 The `rot13Reader` type is provided for you.
378 Make it an `io.Reader` by implementing its `Read` method.
379
380 .play methods/exercise-rot-reader.go
381
382 * Images
383
384 [[/pkg/image/#Image][Package image]] defines the `Image` interface:
385
386 package image
387
388 type Image interface {
389 ColorModel() color.Model
390 Bounds() Rectangle
391 At(x, y int) color.Color
392 }
393
394 *Note*: the `Rectangle` return value of the `Bounds` method is actually an
395 [[/pkg/image/#Rectangle][`image.Rectangle`]], as the
396 declaration is inside package `image`.
397
398 (See [[/pkg/image/#Image][the documentation]] for all the details.)
399
400 The `color.Color` and `color.Model` types are also interfaces, but we'll ignore that by using the predefined implementations `color.RGBA` and `color.RGBAModel`. These interfaces and types are specified by the [[/pkg/image/color/][image/color package]]
401
402 .play methods/images.go
403
404 * Exercise: Images
405
406 Remember the [[/tour/moretypes/18][picture generator]] you wrote earlier? Let's write another one, but this time it will return an implementation of `image.Image` instead of a slice of data.
407
408 Define your own `Image` type, implement [[/pkg/image/#Image][the necessary methods]], and call `pic.ShowImage`.
409
410 `Bounds` should return a `image.Rectangle`, like `image.Rect(0,`0,`w,`h)`.
411
412 `ColorModel` should return `color.RGBAModel`.
413
414 `At` should return a color; the value `v` in the last picture generator corresponds to `color.RGBA{v,`v,`255,`255}` in this one.
415
416 .play methods/exercise-images.go
417
418 * Congratulations!
419
420 You finished this lesson!
421
422 You can go back to the list of [[/tour/list][modules]] to find what to learn next, or continue with the [[javascript:click('.next-page')][next lesson]].
423
View as plain text