# publicmiekg/gobook

### Subversion checkout URL

You can clone with HTTPS or Subversion.

Fetching contributors…

Cannot retrieve contributors at this time

file 383 lines (342 sloc) 13.72 kb
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 \epi{Go has pointers but not pointer arithmetic. You cannot use a pointervariable to walk through the bytes of a string.}{\textit{Go For C++Programmers}\\{\textsc{GO AUTHORS}}}\noindent{}Go has pointers.There is however no pointer arithmetic, so they act more likereferences than pointers that you may know from C. Pointers are are useful.Remember that when you call a function in Go, the variables are\emph{pass-by-value}. So, for efficiency and the possibility to modify apassed value \emph{in} functions we have pointers.Just like in C you declare a pointer by prefixing the type with an'\key{*}':\lstinline{var p *int}. Now \var{p} is a pointer to an integer value.All newly declared variables are assigned their zero value and pointersare no difference. A newly declared, or just a pointer that points tonothing has a \first{nil}{nil}-value. In other languages this is often calleda NULL pointer in Go it is just \var{nil}. To make a pointer point to something you can use the \first{address-of operator}{operator!address-of}(\func{\&}), which we do on line 5:\begin{lstlisting}[caption=Make use of a pointer,numbers=right,label=src:pointers]var p *intfmt.Printf("%v", p) |\coderemark{Prints \var{nil}}|var i int |\coderemark{Declare integer variable \var{i}}|p = &i |\coderemark{Make \var{p} point to \var{i}}|fmt.Printf("%v", p) |\coderemark{Prints something like \var{0x7ff96b81c000a}}|\end{lstlisting}More general: \var{*X} is a pointer to an \type{X}; \var{[3]X} is anarray of three \type{X}s. Thetypes are therefore really easy to read just read out the names of thetype modifiers: \type{[]} declares an array slice;'\key{*}'declares a pointer; \type{[size]} declares an array. So\type{[]*[3]*X} is an array slice of pointers to arrays of threepointers to \type{X}s (also see figure \ref{fig:pointers}).\begin{figure}[h]\caption[Pointers and types]{Pointers and types, the values \var{v} all have type \type{X}}\label{fig:pointers}\begin{center}\includegraphics[scale=0.65]{fig/pointers.pdf}\end{center}\end{figure}Dereferencing a pointer is done by prefixing the pointer variable with'\type{*}':\begin{lstlisting}[caption=Dereferencing a pointer,label=src:deref]p = &i |\coderemark{Take the address of \var{i}}|*p = 8 |\coderemark{Change the value of \var{i}}|fmt.Printf("%v\n", *p) |\coderemark{Prints 8}|fmt.Printf("%v\n", i) |\coderemark{Idem}|\end{lstlisting}As said, there is no pointer arithmetic, so if you write:\lstinline{*p++}, it is interpreted as \lstinline{(*p)++}: firstdeference and then increment the value.\index{operator!increment}\section{Allocation}Go has garbage collection, meaning that you don't have to worry aboutmemory allocation and deallocation. Of course almost every languagesince 1980 has this, but it is nice to see garbage collection in aC-like language.Go has two allocation primitives, \key{new} and \key{make}. They do differentthings and apply to different types, which can be confusing, but therules are simple.The following sections show how to handle allocationin Go and hopefully clarifies the somewhat artificial distinction between\first{\key{new}}{built-in!new} and \first{\key{make}}{built-in!make}. \subsection{Allocation with new}\label{sec:allocation with new}The built-in function \key{new} is essentially the same as its namesakes in other languages: \func{new(T)}allocates zeroed storage for a new item of type \type{T} and returns itsaddress, a value of type \type{*T}. In Go terminology, it returns a pointer toa newly allocated zero value of type \type{T}. This is important toremember:\begin{lbar}\key{new} returns \emph{pointers}.\end{lbar}Thismeans a user of the data structure can create one with \key{new} and getright to work. For example, the documentation for \func{bytes.Buffer} statesthat "the zero value for Buffer is an empty buffer ready to use."Similarly, \func{sync.Mutex} does not have an explicit constructor or Initmethod. Instead, the zero value for a \func{sync.Mutex} is defined to be anunlocked mutex.The zero-value-is-useful property works transitively. Consider this typedeclaration.\begin{lstlisting}type SyncedBuffer struct {    lock sync.Mutex    buffer bytes.Buffer}\end{lstlisting}Values of type \type{SyncedBuffer} are also ready to use immediately uponallocation or just declaration. In this snippet, both \var{p} and\var{v} will workcorrectly without further arrangement.\begin{lstlisting}p := new(SyncedBuffer) // type *SyncedBuffervar v SyncedBuffer // type SyncedBuffer\end{lstlisting}\subsection{Allocation with make}\label{sec:allocation with make}Back to allocation. The built-in function \func{make(T, args)} serves a purposedifferent from \func{new(T)}. It creates slices, maps, and channels only, andit returns an initialized (not zero) value of type \type{T}, not\type{*T}. The reasonfor the distinction is that these three types are, under the covers,references to data structures that must be initialized before use. Aslice, for example, is a three-item descriptor containing a pointer tothe data (inside an array), the length, and the capacity; until thoseitems are initialized, the slice is \type{nil}. For slices, maps, and channels,\key{make} initializes the internal data structure and prepares the value foruse. \begin{lbar}\key{make} returns initialized (non zero) \emph{values}.\end{lbar}For instance,\lstinline{make([]int, 10, 100)}allocates an array of 100 ints and then creates a slice structure withlength 10 and a capacity of 100 pointing at the first 10 elements of thearray. In contrast,\lstinline{new([]int)} returnsa pointer to a newly allocated, zeroed slice structure, that is, apointer to a \type{nil} slice value.These examples illustrate the difference between \key{new()} and\key{make()}.\begin{lstlisting}var p *[]int = new([]int) // allocates slice structure; *p == nil // rarely usefulvar v []int = make([]int, 100) // v refers to a new array of 100 ints// Unnecessarily complex:var p *[]int = new([]int)*p = make([]int, 100, 100)// Idiomatic:v := make([]int, 100)\end{lstlisting}Remember that \key{make()} applies only to maps, slices and channels and doesnot return a pointer. To obtain an explicit pointer allocate with\key{new()}.\subsection{Constructors and composite literals}Sometimes the zero value isn't good enough and an initializingconstructor is necessary, as in this example taken from the package\package{os}.\begin{lstlisting}func NewFile(fd int, name string) *File {    if fd < 0 {        return nil    }    f := new(File)    f.fd = fd    f.name = name    f.dirinfo = nil    f.nepipe = 0    return f}\end{lstlisting}There's a lot of boiler plate in there. We can simplify it using acomposite literal, which is an expression that creates a new instanceeach time it is evaluated.\begin{lstlisting}func NewFile(fd int, name string) *File {    if fd < 0 {        return nil    }    f := File{fd, name, nil, 0} |\coderemark{Create a new \type{File}}|    return &f |\coderemark{Return the address of \var{f}}|}\end{lstlisting}Note that it's perfectly OK to return the address of a local variable;the storage associated with the variable survives after the functionreturns. In fact, taking the address of a composite literal allocates afresh instance each time it is evaluated, so we can combine these lasttwo lines.\begin{lstlisting}return &File{fd, name, nil, 0}\end{lstlisting}The fields of a composite literal are laid out in order and must all bepresent. However, by labeling the elements explicitly as field:valuepairs, the initializers can appear in any order, with the missing onesleft as their respective zero values. Thus we could say\begin{lstlisting}return &File{fd: fd, name: name}\end{lstlisting}As a limiting case, if a composite literal contains no fields at all, itcreates a zero value for the type. The expressions\lstinline{new(File)} and \lstinline|&File{}| are equivalent.Composite literals can also be created for arrays, slices, and maps,with the field labels being indices or map keys as appropriate. In theseexamples, the initializations work regardless of the values of\var{Enone},\var{Eio}, and \var{Einval}, as long as they are distinct.\begin{lstlisting}ar := [...]string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}sl := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}ma := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}\end{lstlisting}\section{Defining your own}\label{sec:defining your own}\todo{tags in structs}Of course Go allows you to define new types, it does this with the \first{\key{type}}{keyword!type} keyword: \begin{lstlisting}type foo int\end{lstlisting}Createsa new type \lstinline{foo} which acts like an \lstinline{int}.Creating more sophisticated types is done with the\first{\key{struct}}{keyword!struct}keyword.An example would be when we want record somebody's name (\type{string})and age (\type{int}) in a single structure and make it a new type:\lstinputlisting[label=src:struct,caption=Structures]{src/struct.go}Apropos, the output of \lstinline{fmt.Printf("%v\n", a)} is \begin{display}{Pete, 42}\end{display}That is nice!Go knows how to print your structure. If youonly want to print one, or a few, fields of the structure you'llneed to use \verb|.|. For example to only print the name:\begin{lstlisting}fmt.Printf("%s", a.name) |\coderemark{\%s formats a string}|\end{lstlisting}\todo{Struct with exported fields}\subsection{Methods}\label{sec:methods}If you create functions that works on your newly defined type, you cantake two routes:\begin{enumerate}\item Create a function that takes the type as an argument.\begin{lstlisting}func doSomething(in1 *NameAge, in2 int) { /* ... */ }\end{lstlisting}This is (you might have guessed) a \first{\emph{function call}}{function!call}.\item Create a function that works on the type (see \emph{receiver} inlisting \ref{src:function definition}):\begin{lstlisting}func (in1 *NameAge) doSomething(in2 int) { /* ... */ }\end{lstlisting}This is a \first{\emph{method call}}{method call}, which can beused as: \begin{lstlisting}var n *NameAgen.doSomething(2)\end{lstlisting}\end{enumerate}But keep the following in mind, this is quoted from \cite{go_spec}:\begin{quote}If \type{x} isaddressable and \lstinline{&x}'s method set contains \func{m}, \lstinline{x.m()} is shorthand for \lstinline{(&x).m()}.\end{quote}In the above case this means that the following is \emph{not} an error:\begin{lstlisting}var n NameAge |\coderemark{Not a pointer}|n.doSomething(2) \end{lstlisting}Here Go will search the method list for \var{n} of type \type{NameAge},come up empty and will then \emph{also} search the method list forthe type \type{*NameAge} and will translate this call to\lstinline{(&n).doSomething(2)}.\section{Conversions}\label{sec:conversions}Sometimes you want to convert a type to another type. In C this is knownas casting a value to another type. This is also possible in Go, butthere are some rules. For starters, converting from one value to anotheris done by functions and not all conversions are allowed.\begin{table}[H]\begin{center}\caption{Valid conversions}\label{tab:convesion}\input{tab/conversion.tex}\end{center}\end{table}\begin{itemize}\item{From a \lstinline{string} to a slice of bytes or ints.\begin{lstlisting}mystring := "hello this is string"\end{lstlisting}\begin{lstlisting}byteslice := []byte(mystring)\end{lstlisting}Converts to a \type{byte} slice, each \type{byte} contains the integer valueof the corresponding byte in the string. Note that as strings in Goare encoded in UTF-8 some characters in the string may end up in 1, 2, 3or 4 bytes.\begin{lstlisting}intslice := []int(mystring)\end{lstlisting}Converts to an \type{int} slice, each \type{int} contains a Unicode codepoint. Every character from the string is corresponds to one integer.}\item{From a slice of bytes or ints to a \lstinline{string}.\begin{lstlisting}b := []byte{'h','e','l','l','o'} |\coderemark{Composite literal}|s := string(b)i := []int{257,1024,65} r := string(i)\end{lstlisting}}\end{itemize}For numeric values the following conversion are defined:\begin{itemize}\item{Convert to a integer with a specific (bit) length: \lstinline{uint8(int)};}\item{From floating point to an integer value: \lstinline{int(float)}. This discards the fraction partfrom the floating point value;}\item{The other way around: \lstinline{float(int)};}\end{itemize}\subsection{User defined types}\todo{Make the text flow more nicely into this paragraph.}\todo{CHECK THIS.}We create two types here \type{Foo} and \type{Bar}, where\lstinline{Bar} is an alias for \type{Foo}:\begin{lstlisting}type foo struct { int } type bar foo\end{lstlisting}Then we:\begin{lstlisting}var b bar = bar{1} |\coderemark{Declare \var{b} to be a \type{bar}}|var f foo = b |\coderemark{Assign \var{b} to \var{f}}|\end{lstlisting}Which fails on the last line with:\noindent\error{cannot use b (type bar) as type foo in assignment}This can be fixed with a conversion:\begin{lstlisting}var f foo = foo(b)\end{lstlisting}\section{Exercises}\input{ex-beyond/ex-map.tex}\input{ex-beyond/ex-pointers.tex}\input{ex-beyond/ex-pointers-and-reflect.tex}\input{ex-beyond/ex-double-linked-list.tex}\input{ex-beyond/ex-cat.tex}\input{ex-beyond/ex-pointers-method.tex}\cleardoublepage\section{Answers}\shipoutAnswer
Something went wrong with that request. Please try again.