Go Language Study Notes - Chapter 6 Method (The Go Programming Language)

Chapter 6 Methods

  • A method is a function associated with a particular type
  • To the two key points of OOP programming, encapsulation and composition

Common libraries and methods

  • time.Duration time.Hour time.Duration.Seconds()

6.1 Method declaration

focus

  • When a function is declared, put a variable before its name, which is a method
  • The receiver of golang is not like thisthe sum of other languages self, which can be chosen arbitrarily. In order to keep the shortness of the new one passed between methods, it is recommended to use the first letter of the first letter of the type in lowercase.
  • p.DistanceThe expression is called a selector, and the selector will also be used to select a field of type struct
  • Since the methods and fields are in the same namespace, the names of the methods and fields should not be the same, otherwise the compilation will not pass
  • Different types have different namespaces, which means that different types can have methods with the same name
  • Unlike other OOP languages, Go language can specify methods for any type, so it is convenient to define some methods for simple values, strings, slices, and maps in Go language. Methods can be declared on any type, as long as it is not a pointer or an interface

Common libraries and methods

  • math.Hypot

6.2 Pointer-based methods

focus

  • The name of the method is (*Point).ScaleBy. The parentheses here are required; without them the expression might be interpreted as *(Point.ScaleBy).
  • Only types (Point) and pointers to them (*Point) are the two types of receivers that may appear in receiver declarations
  • In order to avoid ambiguity, when declaring a method, if a type name itself is a pointer, it is not allowed to appear in the receiver, such as
type P *int
func (P) f() { /* ... */ } // compile error: invalid receiver >type
  • If the receiver needs a pointer as the receiver, the Go language can directly use the type variable + selector to call the method, because the Go language compiler will implicitly use the variable to &call this method, also for the receiver of the type variable, the pointer variable It can be used directly when calling, and the compiler will add it *. for example:
方法(类型变量直接作为指针接收器调用):
func (p *Point) ScaleBy(factor float64)
----
p := Point{1, 2}
p.ScaleBy(2)  //是允许的,编译器会使用&p去调用
----
方法(类型指针直接作为类型变量接收器调用):
func (p Point) Distance(q Point) float64
----
p := Point{1, 2}
pptr := &p
pptr.Distance(q) //是允许的,编译器会使用*pptr去调用

This way of writing is only applicable to "variables" - elements in fields, arrays, and slices, butcannot call a pointer method through a receiver whose address cannot be taken, for example, the memory address of the temporary variable cannot be obtained, and the following call is wrong:

Point{1, 2}.ScaleBy(2) // compile error: can't take address of >Point literal
--------下面的这个是可以的,因为Distance()的接收器是类型变量
Point{1, 2}.Distance(q) // it's ok
  • When the receiver is a type variable, the method operates on a copy of the object; when the receiver is a pointer, the method operates on a reference to the object, and changes to members will be applied to the object.
  • Summarize:
    • Regardless of whether the receiver of your method is a pointer type or a non-pointer type, it can be called through a pointer/non-pointer type, and the compiler will help you do type conversion.
    • When declaring whether the receiver of a method should be a pointer or a non-pointer type, you need to consider two aspects. The first aspect is whether the object itself is particularly large. If it is declared as a non-pointer variable, the call will generate a copy; the second The second aspect is that if you use a pointer type as a receiver, then you must pay attention that this pointer type always points to a memory address, even if you copy it. Those familiar with C or C++ should be able to understand it quickly here.
    • Array, slice, map These types are used as receivers, whether they are variables or pointers, they all represent a pointer

6.2.1 Nil is also a legal receiver type

focus

  • A method can theoretically also use a nil pointer as its receiver, especially when nil is a legal zero value for an object, such as a map or slice

6.3 Extending types by embedding structs

focus

  • Structure SEmbedding The structure Tcan be an anonymous field or a named field. Assuming Tthere are members M, the method of the named field cannot be S.Mcalled directly, but can only be S.Tname.Mcalled.
  • The embedded structure can be understood as a kind of inheritance, but it is somewhat different from inheritance, namely: inheritance in other languagesis "is a", and the embedded structure of Go languageis "has a". That is to say, the new type cannot replace the embedded type and be directly passed to the method that requires the embedded type parameter, and the embedded type must be explicitly selected. for example:
var p = ColoredPoint{Point{1, 1}, red}
var q = ColoredPoint{Point{5, 4}, blue}

p.Distance(q) // compile error: cannot use q (ColoredPoint) as >Point
p.Distance(q.Point) // compile success.
  • Given the following example, all the members and methods owned can be ColoredPointobtained through or directly :PointColoredPoint.Point.XColoredPoint.XX
type Point struct{ X, Y float64 }
type ColoredPoint struct {
Point
Color color.RGBA
}
  • Embedded anonymous fields may also be pointers to a named type, in which case fields and methods are indirectly introduced into the current type, allowing us to share common structures and dynamically change relationships between objects
  • A struct type may also have multiple anonymous fields
  • When the compiler resolves a selector to a method, it will first look for the methods directly defined in this
    type , then find the methods introduced by the embedded fields, then find the methods introduced by the embedded fields of the embedded fields, and then Keep looking down recursively. If the selector is ambiguous, the compiler will report an error. For example, if you have two methods with the same name at the same level, you need to explicitly specify the anonymous field until there is no ambiguity.
  • In the book, the difference between the function and method defined by the author refers to whether there is a receiver, instead of referring to whether there is a return value as in other languages.
  • When Tit is a type, the method expression may be written T.for (*T).f, will return a function "value", this function will use its first parameter as a receiver, so Point.Distanceit can be used directly as a function, cross-package calls also need plus package namepackage.Point.Distance

6.4 Method values ​​and method expressions

focus

  • Method Value - "Method Value"
distanceFromP := p.Distance // method value
distanceFromPValue := p.Distance() // method result

6.5 Example: Bit Array

Key
common libraries and methods

  • bytes.Buffer bytes.Buffer.WriteByte

6.6 Packaging

focus

  • An object's variables or methods are generally defined as "encapsulated" if they are not visible to the caller
  • The Go language has only one means of controlling visibility: uppercase identifiers are exported from the package in which they are defined, lowercase identifiers are not. The same applies to struct or a method of type
  • In Go language, if we want to encapsulate an object, we must define it as a struct.
  • This name-based approach makes the smallest unit of encapsulation in the language a package, rather than a type like in other languages.
  • A field of type struct is visible to all code in the same package, whether your code is written in a function or a method.
  • Encapsulation offers three advantages.
    • First, because the caller cannot directly modify the variable values ​​of the object, it only needs to pay attention to a small number of statements and understand the possible values ​​of a small number of variables.
    • Second, hiding the details of the implementation can prevent the caller from relying on the specific implementations that may change, so that the programmers who design the package can get greater freedom without breaking the external API.
    • Third, it prevents the external caller from arbitrarily modifying the value inside the object.
  • Functions that only access or modify internal variables are called setters or getters

Guess you like

Origin blog.csdn.net/rabbit0206/article/details/103758434