├── main.go ├── main_ffi.go └── main_test.go /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "reflect" 7 | "sort" 8 | "sync" 9 | "time" 10 | "unicode/utf8" 11 | ) 12 | 13 | func main() { 14 | 15 | // variable declarations 16 | var number int = 1 17 | var one, two = 1, 2 18 | three := 3 19 | 20 | // unused variables produce compilation errors 21 | fmt.Println(number + one + two + three) 22 | 23 | // arrays have a fixed length 24 | var array [2]int 25 | fmt.Printf("array of %v elements\n", len(array)) 26 | 27 | // array literals 28 | _ = [3]int{1, 2, 3} 29 | _ = [...]int{1, 2, 3, 4} 30 | _ = [...]int{2: 10, 4: 20} 31 | 32 | // slices have an auto growing length 33 | // they keep track of an array and its capacity 34 | var slice []int 35 | fmt.Printf("slice of %v elements and a capacity for %v\n", len(slice), cap(slice)) 36 | 37 | // slice literals 38 | _ = []int{} 39 | _ = []int{1, 2, 3, 4} 40 | _ = []int{2: 10, 4: 20} 41 | 42 | // appending values 43 | // can reallocate the array to a bigger location 44 | // must be recaptured 45 | slice = append(slice, 1) 46 | slice = append(slice, 2) 47 | slice = append(slice, 3) 48 | fmt.Printf("appended slice %v\n", slice) 49 | 50 | // selecting values 51 | fmt.Printf("selected slice %v\n", array[1:]) 52 | 53 | // modifying values 54 | slice[0] = 10 55 | slice[1] = 20 56 | slice[2] = 30 57 | fmt.Printf("modified slice %v\n", slice) 58 | 59 | // removing values 60 | copy(slice[1:], slice[2:]) 61 | slice = slice[:len(slice)-1] 62 | fmt.Printf("removed slice %v\n", slice) 63 | 64 | // slices can be built with a 65 | // predefined length and capacity 66 | slice = make([]int, 5, 1000) 67 | fmt.Printf("slice of %v elements and a capacity for %v\n", len(slice), cap(slice)) 68 | 69 | // selected slices are not stable 70 | // changes in the source can be seen 71 | // unless the source gets reallocated 72 | // probably make a copy 73 | source := []int{1} 74 | selectedSlice := source[:] 75 | source[0] = 2 76 | fmt.Printf("selected slice %v\n", selectedSlice) 77 | source = append(source, 0) 78 | source[0] = 3 79 | fmt.Printf("selected slice %v\n", selectedSlice) 80 | 81 | // maps are hash tables 82 | var nameById = make(map[int]string) 83 | 84 | // map literals 85 | _ = map[int]string{} 86 | _ = map[int]string{1: "Alice", 2: "Bob"} 87 | 88 | // setting values 89 | nameById[100] = "Alice" 90 | nameById[200] = "Bob" 91 | nameById[300] = "Carl" 92 | 93 | // looking up values 94 | if name, ok := nameById[100]; ok { 95 | fmt.Printf("name: %v\n", name) 96 | } 97 | 98 | // iterating over values 99 | // order is not guaranteed 100 | for id, name := range nameById { 101 | fmt.Printf("id: %v, name: %v\n", id, name) 102 | } 103 | 104 | // removing values 105 | delete(nameById, 300) 106 | 107 | // strings are immutable sequences of bytes 108 | greek := "some greek: Τη γλώσσα μου έδωσαν" 109 | 110 | // the index operation returns a byte 111 | fmt.Println(greek[0]) 112 | 113 | // the substring operation returns a string 114 | fmt.Println(greek[5:10]) 115 | 116 | // strings can be decoded as bytes 117 | greekBytes := []byte(greek) 118 | fmt.Printf("greek decoded as bytes: %v\n", greekBytes) 119 | 120 | // or as utf8 unicode code points 121 | // these are named runes and are int32 122 | greekRunes := []rune(greek) 123 | fmt.Printf("greek decoded as runes: %v\n", greekRunes) 124 | 125 | // fancy decoding is required to 126 | // index the runes inside a string 127 | rune, bytesCount := utf8.DecodeRuneInString(greek[14:]) 128 | runesCount := utf8.RuneCountInString(greek) 129 | fmt.Printf("found rune %c spanning %v bytes\n", rune, bytesCount) 130 | fmt.Printf("found %v runes\n", runesCount) 131 | 132 | // iterating is done over runes 133 | for range greek { 134 | } 135 | 136 | // efficient string building using a buffer 137 | var buffer bytes.Buffer 138 | buffer.WriteByte('a') 139 | buffer.WriteRune('λ') 140 | buffer.WriteString("yeah") 141 | fmt.Println(buffer.String()) 142 | 143 | // structure definitions 144 | type Employee struct { 145 | EmployeeID int 146 | FirstName string 147 | LastName string 148 | } 149 | 150 | // structure literals 151 | _ = Employee{1, "Alice", "Alisson"} 152 | _ = Employee{FirstName: "Alice"} 153 | 154 | // structure allocations 155 | _ = new(Employee) 156 | _ = &Employee{2, "Bob", "Bobson"} 157 | _ = &Employee{FirstName: "Bob"} 158 | 159 | // accessing fields 160 | var employee Employee = Employee{FirstName: "A"} 161 | fmt.Printf("employee first name: %v\n", employee.FirstName) 162 | 163 | // same notation with pointers 164 | var employeePointer *Employee = &employee 165 | fmt.Printf("employee first name: %v\n", employeePointer.FirstName) 166 | 167 | // structures are passed by value 168 | // but are primarily used with pointers 169 | type Team struct { 170 | Manager *Employee 171 | Employees []*Employee 172 | } 173 | 174 | // anonymous structures 175 | var point struct{ X, Y int } 176 | point.X = 100 177 | 178 | // anonymous structure literals 179 | _ = struct{ X, Y, Z int }{X: 1, Y: 2, Z: 3} 180 | 181 | // named types 182 | type ShoeSize int 183 | var _ ShoeSize = ShoeSize(14) 184 | 185 | // something like an enum 186 | type Flavor int32 187 | const ( 188 | Vanilla Flavor = iota 189 | Chocolate 190 | Pistachios 191 | ) 192 | var bestFlavor Flavor = Chocolate 193 | fmt.Printf("bestFlavor: %v\n", bestFlavor) 194 | 195 | // see you later 196 | later() 197 | } 198 | 199 | // function signatures 200 | func noReturn() { 201 | } 202 | func oneReturn() bool { 203 | return false 204 | } 205 | func multipleReturns() (bool, int) { 206 | return true, 25 207 | } 208 | func bareReturns() (x, y int) { 209 | x = 1 210 | y = 2 211 | return 212 | } 213 | 214 | // there is no tail call optimization 215 | // but we get auto-growing stacks 216 | func recurse(x int) { 217 | if x < 1000 { 218 | recurse(x + 1) 219 | } 220 | } 221 | 222 | // error handling 223 | func ooops() error { 224 | return fmt.Errorf("damn thing exploded") 225 | } 226 | func errorPropagation() error { 227 | err := ooops() 228 | if err != nil { 229 | return err 230 | } 231 | return nil 232 | } 233 | func errorWithContext(color string) error { 234 | err := ooops() 235 | if err != nil { 236 | return fmt.Errorf("while trying to paint %s: %v", color, err) 237 | } 238 | return nil 239 | } 240 | 241 | // functions as values 242 | func addNumbers(x, y int) int { 243 | return x + y 244 | } 245 | 246 | func later() { 247 | 248 | // returns 249 | noReturn() 250 | _ = oneReturn() 251 | _, _ = multipleReturns() 252 | _, _ = bareReturns() 253 | 254 | // functions as values 255 | var functionAsValue func(int, int) int = addNumbers 256 | fmt.Println(functionAsValue(1, 2)) 257 | 258 | // anonymous functions 259 | plusOne := func(x int) int { return x + 1 } 260 | fmt.Println(plusOne(1)) 261 | 262 | // closures 263 | someNumber := 25 264 | plusTwo := func() int { return someNumber + 2 } 265 | fmt.Println(plusTwo()) 266 | 267 | // but by reference 268 | someNumber = 50 269 | fmt.Println(plusTwo()) 270 | 271 | // leading to weird patterns 272 | // where closed values need to be copied 273 | plusThreeNumber := someNumber 274 | plusThree := func() int { return plusThreeNumber + 3 } 275 | someNumber = 75 276 | fmt.Println(plusThree()) 277 | 278 | // variadic functions 279 | bigCompute := func(values ...int) int { 280 | return len(values) 281 | } 282 | bigComputeValues := []int{1, 2, 3} 283 | fmt.Println(bigCompute(1, 2, 3)) 284 | fmt.Println(bigCompute(bigComputeValues...)) 285 | 286 | // deferred function calls 287 | doStuff := func() { 288 | fmt.Println("enter") 289 | defer fmt.Println("executed when the function exits") 290 | { 291 | defer fmt.Println("not when a block exits") 292 | } 293 | fmt.Println("exit") 294 | } 295 | doStuff() 296 | 297 | // panicking 298 | ohNoes := func() { 299 | panic("we are screwed") 300 | } 301 | 302 | // recovering 303 | keepCalm := func() { 304 | defer func() { 305 | whatNow := recover() 306 | fmt.Println(whatNow) 307 | }() 308 | ohNoes() 309 | fmt.Println("too bad won't execute") 310 | } 311 | keepCalm() 312 | 313 | laterr() 314 | } 315 | 316 | type Animal struct { 317 | LegsCount int 318 | } 319 | 320 | // methods are attached to a receiver type 321 | func (a *Animal) CanQuack() bool { 322 | return false 323 | } 324 | 325 | // receivers are primarily pointers 326 | // to allow state mutations 327 | func (a *Animal) GrowLeg() { 328 | a.LegsCount++ 329 | } 330 | 331 | func laterr() { 332 | 333 | // methods 334 | animal := &Animal{4} 335 | fmt.Println(animal.CanQuack()) 336 | 337 | // structure embedding 338 | type Dog struct { 339 | Animal 340 | GoodBoyName string 341 | } 342 | 343 | // the structure gains all 344 | // the members of the embedded one 345 | fido := &Dog{Animal{4}, "Fido"} 346 | fmt.Printf("legs count: %v\n", fido.LegsCount) 347 | fmt.Printf("good boy name: %v\n", fido.GoodBoyName) 348 | 349 | // including its attached methods 350 | fido.GrowLeg() 351 | 352 | // the embedded structure 353 | // can be accessed explicitly 354 | var _ *Animal = &fido.Animal 355 | 356 | // converting from method to a function 357 | // taking the receiver as first parameter 358 | methodExpression := (*Animal).GrowLeg 359 | methodExpression(animal) 360 | 361 | // converting from method to a function 362 | // with the receiver already bound 363 | methodValue := animal.GrowLeg 364 | methodValue() 365 | 366 | laterrr() 367 | } 368 | 369 | // encapsulation 370 | // members starting with a lower cased letter 371 | // are only visible inside their package 372 | type Cake struct { 373 | hugeCaloriesCount int 374 | } 375 | 376 | // getters and setters 377 | func (cake *Cake) HugeCaloriesCount() int { 378 | return cake.hugeCaloriesCount 379 | } 380 | func (cake *Cake) SetHugeCaloriesCount(value int) { 381 | cake.hugeCaloriesCount = value 382 | } 383 | 384 | // interfaces 385 | type Quacker interface { 386 | Quack(times int) 387 | } 388 | 389 | // uses duck typing 390 | // you have the methods you qualify 391 | type Duck struct{} 392 | 393 | func (duck *Duck) Quack(times int) { 394 | for i := 0; i < times; i++ { 395 | fmt.Printf("quack") 396 | } 397 | } 398 | 399 | func laterrr() { 400 | 401 | // visible inside this package 402 | var hugeCake = &Cake{100000} 403 | _ = hugeCake.hugeCaloriesCount 404 | 405 | // any type with a Quack method can be passed 406 | doTheQuacking := func(quacker Quacker, times int) { 407 | quacker.Quack(times) 408 | } 409 | duck := &Duck{} 410 | doTheQuacking(duck, 3) 411 | 412 | // the empty interface 413 | // everyone can play 414 | var empty interface{} 415 | empty = false 416 | empty = 10 417 | empty = duck 418 | _ = empty 419 | 420 | // an interface that is nil 421 | var nilInterface Quacker = nil 422 | if nilInterface != nil { 423 | fmt.Println("will not execute") 424 | } 425 | 426 | // an interface that points to nil 427 | // never do that 428 | var nilDuck *Duck = nil 429 | nilInterface = nilDuck 430 | if nilInterface != nil { 431 | fmt.Println("will execute") 432 | } 433 | 434 | laterrrr() 435 | } 436 | 437 | type Cookie struct { 438 | Size int 439 | Flavour string 440 | Rating int 441 | } 442 | 443 | type CookieSlice []*Cookie 444 | 445 | // any type with these 446 | // methods can be sorted 447 | type CookieBySizeSlice []*Cookie 448 | 449 | func (x CookieBySizeSlice) Len() int { return len(x) } 450 | func (x CookieBySizeSlice) Less(i, j int) bool { return x[i].Size < x[j].Size } 451 | func (x CookieBySizeSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 452 | 453 | // assembling an interface 454 | // from anonymous functions 455 | type FuncSorter struct { 456 | len func() int 457 | less func(i, j int) bool 458 | swap func(i, j int) 459 | } 460 | 461 | func (x *FuncSorter) Len() int { return x.len() } 462 | func (x *FuncSorter) Less(i, j int) bool { return x.less(i, j) } 463 | func (x *FuncSorter) Swap(i, j int) { x.swap(i, j) } 464 | 465 | func laterrrr() { 466 | 467 | // sort them cookies 468 | cookies := CookieSlice{{10, "Chocolate", 5}, {12, "Peanuts", 4}, {8, "Almonds", 3}} 469 | sort.Sort(CookieBySizeSlice(cookies)) 470 | 471 | // sort any slice by any order 472 | sort.Sort(&FuncSorter{ 473 | func() int { return len(cookies) }, 474 | func(i, j int) bool { return cookies[i].Rating < cookies[j].Rating }, 475 | func(i, j int) { cookies[i], cookies[j] = cookies[j], cookies[i] }, 476 | }) 477 | 478 | // type assertions 479 | var quacker Quacker = &Duck{} 480 | if _, ok := quacker.(*Duck); ok { 481 | fmt.Println("is duck") 482 | } 483 | 484 | // type switches 485 | switch x := quacker.(type) { 486 | case *Duck: 487 | fmt.Printf("%v is duck\n", x) 488 | break 489 | default: 490 | fmt.Printf("%v is definitly no duck\n", x) 491 | break 492 | } 493 | 494 | takeNap := func() { 495 | time.Sleep(100 * time.Millisecond) 496 | } 497 | 498 | // functions invoked with 499 | // go are executed concurrently 500 | go takeNap() 501 | go takeNap() 502 | go takeNap() 503 | 504 | // goroutines communicate by 505 | // exchanging messages over channels 506 | channel := make(chan int) 507 | 508 | // both the sender and the receiver are blocked 509 | // until a message is exchanged 510 | sender := func() { 511 | fmt.Println("sending value 1") 512 | channel <- 1 513 | } 514 | 515 | receiver := func() { 516 | value := <-channel 517 | fmt.Printf("received value %v\n", value) 518 | } 519 | 520 | go sender() 521 | go receiver() 522 | time.Sleep(1 * time.Second) 523 | 524 | // a channel can be closed to signal 525 | // no more messages will be sent 526 | sender = func() { 527 | fmt.Println("closing channel") 528 | close(channel) 529 | } 530 | 531 | receiver = func() { 532 | if _, ok := <-channel; !ok { 533 | fmt.Println("channel was closed") 534 | } 535 | } 536 | 537 | go sender() 538 | go receiver() 539 | time.Sleep(1 * time.Second) 540 | channel = make(chan int) 541 | 542 | // loop of messages 543 | // the range automatically breaks 544 | // when the channel closes 545 | sender = func() { 546 | for i := 0; i < 5; i++ { 547 | fmt.Printf("sending value %v\n", i) 548 | channel <- i 549 | } 550 | close(channel) 551 | } 552 | 553 | receiver = func() { 554 | for value := range channel { 555 | fmt.Printf("received value %v\n", value) 556 | } 557 | fmt.Println("channel was closed") 558 | } 559 | 560 | go sender() 561 | go receiver() 562 | time.Sleep(1 * time.Second) 563 | channel = make(chan int) 564 | 565 | // looping concurrently 566 | // and receiving the results 567 | workItems := []int{1, 2, 3, 4} 568 | 569 | for _, workItem := range workItems { 570 | go func(capturedWorkItem int) { 571 | fmt.Printf("sending result %v\n", capturedWorkItem) 572 | channel <- capturedWorkItem 573 | }(workItem) 574 | } 575 | 576 | for range workItems { 577 | result := <-channel 578 | fmt.Printf("received result %v\n", result) 579 | } 580 | 581 | close(channel) 582 | channel = make(chan int) 583 | 584 | // controlling concurrency 585 | // with a fixed number of receivers 586 | sender = func() { 587 | for i := 0; i < 5; i++ { 588 | channel <- i 589 | } 590 | close(channel) 591 | } 592 | 593 | indexedReceiver := func(index int) { 594 | for value := range channel { 595 | fmt.Printf("%v received value %v\n", index, value) 596 | } 597 | } 598 | 599 | go sender() 600 | go indexedReceiver(1) 601 | go indexedReceiver(2) 602 | time.Sleep(1 * time.Second) 603 | 604 | // selecting from multiple channels 605 | // blocks until one of them receives a message 606 | channel1 := make(chan int) 607 | channel2 := make(chan int) 608 | 609 | sender = func() { 610 | channel2 <- 1 611 | } 612 | 613 | receiver = func() { 614 | select { 615 | case value := <-channel1: 616 | fmt.Printf("received %v on channel1\n", value) 617 | break 618 | case value := <-channel2: 619 | fmt.Printf("received %v on channel2\n", value) 620 | break 621 | } 622 | } 623 | 624 | go sender() 625 | go receiver() 626 | time.Sleep(1 * time.Second) 627 | 628 | // adding a default branch 629 | // makes select non blocking 630 | receiver = func() { 631 | select { 632 | case _ = <-channel1: 633 | break 634 | default: 635 | fmt.Println("received nothing") 636 | break 637 | } 638 | } 639 | 640 | go receiver() 641 | time.Sleep(1 * time.Second) 642 | close(channel1) 643 | close(channel2) 644 | 645 | // channel types can be used to 646 | // enforce the message directions 647 | var _ chan<- int = channel 648 | var _ <-chan int = channel 649 | 650 | // a buffer size can be set on the channel 651 | // the sender blocks only when the buffer is full 652 | channel = make(chan int, 2) 653 | close(channel) 654 | 655 | // a mutex allows one goroutine at a time 656 | // must be used to protect shared state 657 | var balanceMutex sync.Mutex 658 | balance := 100 659 | 660 | deposit := func(amount int) { 661 | balanceMutex.Lock() 662 | defer balanceMutex.Unlock() 663 | balance += amount 664 | } 665 | 666 | go deposit(15) 667 | go deposit(500) 668 | time.Sleep(1 * time.Second) 669 | 670 | // a read-write mutex allows 671 | // one writer or multiple readers 672 | var readWriteMutex sync.RWMutex 673 | coins := 0 674 | 675 | moreCoins := func(count int) { 676 | readWriteMutex.Lock() 677 | defer readWriteMutex.Unlock() 678 | coins += count 679 | } 680 | 681 | howManyCoins := func() int { 682 | readWriteMutex.RLock() 683 | defer readWriteMutex.RUnlock() 684 | return coins 685 | } 686 | 687 | go moreCoins(15) 688 | go howManyCoins() 689 | go howManyCoins() 690 | time.Sleep(1 * time.Second) 691 | 692 | // a read-write mutex 693 | // for the lazy initialization 694 | // of a read-only state is provided 695 | var onceMutex sync.Once 696 | var lazyInitializedValue int 697 | 698 | getLazyInitializedValue := func() int { 699 | onceMutex.Do(func() { lazyInitializedValue = 10 + 2/7 - 16 }) 700 | return lazyInitializedValue 701 | } 702 | 703 | go getLazyInitializedValue() 704 | go getLazyInitializedValue() 705 | time.Sleep(1 * time.Second) 706 | 707 | // running a program with the race detector 708 | // go run -race 709 | 710 | // using reflection 711 | reflection := func(somethingA, somethingB interface{}) { 712 | 713 | // getting something's type 714 | typeA := reflect.TypeOf(somethingA).Elem() 715 | fmt.Printf("somethingA is a %v\n", typeA.Kind()) 716 | 717 | typeB := reflect.TypeOf(somethingB).Elem() 718 | fmt.Printf("somethingB is a %v\n", typeB) 719 | 720 | // getting something's value 721 | valueA := reflect.ValueOf(somethingA).Elem().Int() 722 | fmt.Printf("somethingA is %v\n", valueA) 723 | 724 | valueB := reflect.ValueOf(somethingB).Elem() 725 | for i := 0; i < valueB.NumField(); i++ { 726 | fmt.Printf("somethingB.%v is %v\n", valueB.Type().Field(i).Name, valueB.Field(i)) 727 | } 728 | 729 | // setting something's value 730 | reflect.ValueOf(somethingA).Elem().Set(reflect.ValueOf(2)) 731 | reflect.ValueOf(somethingB).Elem().FieldByName("X").Set(reflect.ValueOf(10)) 732 | 733 | // accessing field tags 734 | tag := reflect.ValueOf(somethingB).Elem().Type().Field(0).Tag.Get("color") 735 | fmt.Printf("somethingB.X has color %v\n", tag) 736 | } 737 | 738 | number := 1 739 | structure := struct { 740 | X int `color:"red"` 741 | Y int `color:"blue"` 742 | }{1, 2} 743 | 744 | // setting values must be done through a pointer 745 | // always use them for consistency 746 | reflection(&number, &structure) 747 | 748 | fmt.Printf("number is now %v\n", number) 749 | fmt.Printf("structure is now %v\n", structure) 750 | 751 | // calling C code 752 | Print("Hello") 753 | } 754 | -------------------------------------------------------------------------------- /main_ffi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include 4 | // #include 5 | import "C" 6 | import "unsafe" 7 | 8 | // calling C code 9 | func Print(s string) { 10 | cs := C.CString(s) 11 | defer func() { C.free(unsafe.Pointer(cs)) }() 12 | 13 | C.fputs(cs, (*C.FILE)(C.stdout)) 14 | C.fflush((*C.FILE)(C.stdout)) 15 | } 16 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "testing" 7 | ) 8 | 9 | // running tests 10 | // go test 11 | func TestAddition(t *testing.T) { 12 | if 2+2 != 4 { 13 | t.Error("2+2 != 4") 14 | } 15 | } 16 | 17 | func TestTableDriven(t *testing.T) { 18 | var tests = []struct { 19 | input float64 20 | want float64 21 | }{ 22 | {1, 1}, 23 | {2, 4}, 24 | {3, 9}, 25 | } 26 | for _, test := range tests { 27 | if got := math.Pow(test.input, 2); got != test.want { 28 | t.Errorf("math.Sqrt(%v) = %v, want %v", test.input, got, test.want) 29 | } 30 | } 31 | } 32 | 33 | // mocking using global variables 34 | var selectCustomer = func(customerId int) string { 35 | return fmt.Sprintf("SELECT Name FROM Customers WHERE Id = %v;", customerId) 36 | } 37 | 38 | func GetCustomer(customerId int) string { 39 | return "His name is " + selectCustomer(customerId) 40 | } 41 | 42 | func TestGetCustomer(t *testing.T) { 43 | selectCustomerReal := selectCustomer 44 | defer func() { selectCustomer = selectCustomerReal }() 45 | 46 | selectCustomer = func(customerId int) string { return "Bob" } 47 | 48 | got := GetCustomer(1) 49 | fmt.Printf("got %v\n", got) 50 | } 51 | 52 | // computing test coverage 53 | // and displaying the green/red source 54 | // go test -coverprofile=cover.out 55 | // go tool cover -html=cover.out 56 | 57 | // benchmarking time and memory allocations 58 | // go test -bench=. 59 | // go test -bench=. -benchmem 60 | func Lengthy() { 61 | for i := 0; i < 10000000; i++ { 62 | } 63 | } 64 | 65 | func BenchmarkLengthy(b *testing.B) { 66 | for i := 0; i < b.N; i++ { 67 | Lengthy() 68 | } 69 | } 70 | 71 | // profiling CPU, memory and blocking 72 | // go test -bench=. -cpuprofile=cpu.out 73 | // go test -bench=. -memprofile=mem.out 74 | // go test -bench=. -blockprofile=block.out 75 | // go tool pprof -text -nodecount=10 ./cpu.out 76 | 77 | // providing examples 78 | // included in the documentation 79 | // output checked when tests are run 80 | func Division(x, y int) int { 81 | return x / y 82 | } 83 | 84 | func ExampleDivision() { 85 | fmt.Println(Division(4, 2)) 86 | fmt.Println(Division(10, 2)) 87 | // Output: 88 | // 2 89 | // 5 90 | } 91 | --------------------------------------------------------------------------------