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