github.com/brownsys/tracing-framework-go@v0.0.0-20161210174012-0542a62412fe/go/darwin_amd64/misc/tour/content/methods.article (about) 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) // Compile error! 86 ScaleFunc(&v) // 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 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 covers, 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 [[//golang.org/pkg/fmt/#Stringer][`Stringer`]] defined by the [[//golang.org/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 [[/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://golang.org/search?q=Read#Global][many implementations]] of these interfaces, 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 [[//golang.org/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 [[https://golang.org/pkg/io/#Reader][io.Reader]] that wraps another `io.Reader`, modifying the stream in some way. 372 373 For example, the [[https://golang.org/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 [[https://golang.org/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 [[https://golang.org/pkg/image/#Rectangle][`image.Rectangle`]], as the 396 declaration is inside package `image`. 397 398 (See [[https://golang.org/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 [[https://golang.org/pkg/image/color/][image/color package]] 401 402 .play methods/images.go 403 404 * Exercise: Images 405 406 Remember the 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 [[https://golang.org/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 [[/list][modules]] to find what to learn next, or continue with the [[javascript:click('.next-page')][next lesson]].