move: funcs and ptrs to root

This commit is contained in:
Inanc Gumus
2019-04-24 22:32:35 +03:00
parent 2d413beecd
commit 29ddb76546
34 changed files with 941 additions and 453 deletions

View File

@ -0,0 +1,26 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import "fmt"
func showN() {
if N == 0 {
fmt.Println("showN : N is zero, increment it.")
return
}
fmt.Printf("showN : N = %d\n", N)
}
func incrN() {
N++
}
// you cannot declare a function within the same package with the same name
// func incrN() {
// }

View File

@ -0,0 +1,33 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
//
// You need run this program like so:
// go run .
//
// This will magically pass all the go files in the current directory to the
// Go compiler.
//
//
// BUT NOT like so:
// go run main.go
//
// Because, the compiler needs to see global.go too
// It can't magically find global.go — what you give is what you get.
//
package main
// N is a shared counter which is BAD
var N int
func main() {
showN()
incrN()
incrN()
showN()
}

View File

@ -0,0 +1,117 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
//
// You need run this program like so:
// go run .
//
// This will magically pass all the go files in the current directory to the
// Go compiler.
//
//
// BUT NOT like so:
// go run main.go
//
// Because, the compiler needs to see global.go too
// It can't magically find global.go — what you give is what you get.
//
package main
import (
"fmt"
"strconv"
)
func main() {
local := 10
show(local)
incrWrong(local)
fmt.Printf("local → %d\n", local)
// incr(local)
local = incr(local)
show(local)
local = incrBy(local, 5)
show(local)
_, err := incrByStr(local, "TWO")
if err != nil {
fmt.Printf("err → %s\n", err)
}
local, _ = incrByStr(local, "2")
show(local)
// CHAINING
// can't save the number back into main's local
show(incrBy(local, 2))
show(local)
// can't pass the results of the multiple-value returning func
// show(incrByStr(local, "3"))
// can call showErr directly because it accepts the same types
// of parameters as with incrByStr's result values.
// local = sanitize(incrByStr(local, "NOPE"))
// show(local)
local = sanitize(incrByStr(local, "2"))
show(local)
local = limit(incrBy(local, 5), 2000)
show(local)
}
func show(n int) {
// can't access main's local
// fmt.Printf("show : n = %d\n", local)
fmt.Printf("show → n = %d\n", n)
}
// wrong: incr can't access to main's `local`
func incrWrong(n int) {
// n := local
n++
// can't return (there are no result values)
// return n
}
func incr(n int) int {
n++
return n
}
func incrBy(n, factor int) int {
return n * factor
}
func incrByStr(n int, factor string) (int, error) {
m, err := strconv.Atoi(factor)
n = incrBy(n, m)
return n, err
}
func sanitize(n int, err error) int {
if err != nil {
return 0
}
return n
}
func limit(n, lim int) (m int) {
// var m int
m = n
if m >= lim {
m = lim
}
// return m
return
}

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,44 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
in := bufio.NewScanner(os.Stdin)
p := newParser()
for in.Scan() {
p.lines++
d, err := parse(p, in.Text())
if err != nil {
fmt.Println(err)
return
}
if _, ok := p.sum[d.name]; !ok {
p.domains = append(p.domains, d)
}
p.sum[d.name] += d.visits
p.total += d.visits
}
for _, d := range p.domains {
vis := p.sum[d.name]
fmt.Printf("%-25s -> %d\n", d.name, vis)
}
fmt.Printf("\n%-25s -> %d\n", "TOTAL", p.total)
}

View File

@ -0,0 +1,49 @@
package main
import (
"fmt"
"strconv"
"strings"
)
// domain represents a domain log record
type domain struct {
name string
visits int
}
// parser parses a log file and provides an iterator to iterate upon the domains
//
// the parser struct is carefully crafted to be usable using its zero values except the map field
type parser struct {
sum map[string]int // visits per unique domain
domains []domain // unique domain names
total int // total visits to all domains
lines int // number of parsed lines (for the error messages)
}
// newParser creates and returns a new parser.
func newParser() parser {
return parser{sum: make(map[string]int)}
}
// parse parses the given text and returns a domain struct
func parse(p parser, line string) (dom domain, err error) {
// var dom domain
// var err error
fields := strings.Fields(line)
if len(fields) != 2 {
err = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
return
}
name, visits := fields[0], fields[1]
n, err := strconv.Atoi(visits)
if n < 0 || err != nil {
err = fmt.Errorf("wrong input: %q (line #%d)", visits, p.lines)
return
}
return domain{name: name, visits: n}, nil
}

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,39 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
in := bufio.NewScanner(os.Stdin)
p := newParser()
for in.Scan() {
p.lines++
d, err := parse(p, in.Text())
if err != nil {
fmt.Println(err)
return
}
p = push(p, d)
}
for _, d := range p.domains {
vis := p.sum[d.name]
fmt.Printf("%-25s -> %d\n", d.name, vis)
}
fmt.Printf("\n%-25s -> %d\n", "TOTAL", p.total)
}

View File

@ -0,0 +1,59 @@
package main
import (
"fmt"
"strconv"
"strings"
)
// domain represents a domain log record
type domain struct {
name string
visits int
}
// parser parses a log file and provides an iterator to iterate upon the domains
//
// the parser struct is carefully crafted to be usable using its zero values except the map field
type parser struct {
sum map[string]int // visits per unique domain
domains []domain // unique domain names
total int // total visits to all domains
lines int // number of parsed lines (for the error messages)
}
// newParser creates and returns a new parser.
func newParser() parser {
return parser{sum: make(map[string]int)}
}
// parse parses the given text and returns a domain struct
func parse(p parser, line string) (dom domain, err error) {
fields := strings.Fields(line)
if len(fields) != 2 {
err = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
return
}
name, visits := fields[0], fields[1]
n, err := strconv.Atoi(visits)
if n < 0 || err != nil {
err = fmt.Errorf("wrong input: %q (line #%d)", visits, p.lines)
return
}
return domain{name: name, visits: n}, nil
}
// push pushes the given domain to the internal list of domains.
// it also increases the total visits for all the domains.
func push(p parser, d domain) parser {
if _, ok := p.sum[d.name]; !ok {
p.domains = append(p.domains, d)
}
p.sum[d.name] += d.visits
p.total += d.visits
return p
}

View File

@ -0,0 +1,39 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import "fmt"
func main() {
var counter byte = 100
P := &counter
V := *P
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("P : %-16p address: %-16p *P: %-16d\n", P, &P, *P)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
V = 200
fmt.Println()
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("P : %-16p address: %-16p *P: %-16d\n", P, &P, *P)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
V = counter // reset the V to counter's initial value
counter++
fmt.Println()
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("P : %-16p address: %-16p *P: %-16d\n", P, &P, *P)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
*P = 25
fmt.Println()
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("P : %-16p address: %-16p *P: %-16d\n", P, &P, *P)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
}

View File

@ -0,0 +1,63 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import "fmt"
func main() {
var (
counter int
V int
P *int
)
if P == nil {
fmt.Printf("P is nil and its address is %p\n", P)
}
counter = 100 // counter is an int variable
P = &counter // P is a pointer int variable
V = *P // V is a int variable (a copy of counter)
if P == &counter {
fmt.Printf("P's address is equal to counter: %p == %p\n", P, &counter)
}
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("P : %-16p address: %-16p *P: %-16d\n", P, &P, *P)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
fmt.Println("\n••••• CHANGE: counter")
counter = 10 // V doesn't change because it's a copy
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Printf("V : %-16d address: %-16p\n", V, &V)
fmt.Println("\n••••• CHANGE IN: passVal")
counter = passVal(counter)
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
fmt.Println("\n••••• CHANGE IN: passPtrVal")
passPtrVal(&counter) // same as passPtrVal(&counter) (no need to return)
fmt.Printf("counter : %-16d address: %-16p\n", counter, &counter)
}
// *pn is a int pointer variable (copy of P)
func passPtrVal(pn *int) {
fmt.Printf("pn : %-16p address: %-16p *pn: %d\n", pn, &pn, *pn)
// pointers can breach function isolation borders
*pn++ // counter changes because `pn` points to `counter` — (*pn)++
fmt.Printf("pn : %-16p address: %-16p *pn: %d\n", pn, &pn, *pn)
}
// n is a int variable (copy of counter)
func passVal(n int) int {
n = 50 // counter doesn't change because `n` is a copy
fmt.Printf("n : %-16d address: %-16p\n", n, &n)
return n
}

View File

@ -0,0 +1,141 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println("••••• ARRAYS")
arrays()
fmt.Println("\n••••• SLICES")
slices()
fmt.Println("\n••••• MAPS")
maps()
fmt.Println("\n••••• STRUCTS")
structs()
}
// -----------------------------------------------------------------------------
type house struct {
name string
rooms int
}
func structs() {
myHouse := house{name: "My House", rooms: 5}
addRoom(myHouse)
// fmt.Printf("%+v\n", myHouse)
fmt.Printf("structs() : %p %+v\n", &myHouse, myHouse)
addRoomPtr(&myHouse)
fmt.Printf("structs() : %p %+v\n", &myHouse, myHouse)
fmt.Printf("&myHouse.name : %p\n", &myHouse.name)
fmt.Printf("&myHouse.rooms: %p\n", &myHouse.rooms)
}
func addRoom(h house) {
h.rooms++
fmt.Printf("addRoom() : %p %+v\n", &h, h)
}
func addRoomPtr(h *house) {
// (*h).rooms++
h.rooms++
fmt.Printf("addRoomPtr() : %p %+v\n", h, h)
}
// -----------------------------------------------------------------------------
func maps() {
confused := map[string]int{"one": 2, "two": 1}
fix(confused)
fmt.Println(confused)
// &confused["one"]
}
func fix(m map[string]int) {
m["one"] = 1
m["two"] = 2
m["three"] = 3
}
// -----------------------------------------------------------------------------
func slices() {
dirs := []string{"up", "down", "left", "right"}
up(dirs)
fmt.Printf("slices list : %p %q\n", &dirs, dirs)
upPtr(&dirs)
fmt.Printf("slices list : %p %q\n", &dirs, dirs)
}
func up(list []string) {
for i := range list {
list[i] = strings.ToUpper(list[i])
fmt.Printf("up.list[%d] : %p\n", i, &list[i])
}
// *list = append(*list, "HEISEN BUG")
list = append(list, "HEISEN BUG")
fmt.Printf("up list : %p %q\n", &list, list)
}
func upPtr(list *[]string) {
lv := *list
for i := range lv {
lv[i] = strings.ToUpper(lv[i])
}
*list = append(*list, "HEISEN BUG")
fmt.Printf("upPtr list : %p %q\n", list, list)
}
// -----------------------------------------------------------------------------
func arrays() {
nums := [...]int{1, 2, 3}
incr(nums)
fmt.Printf("arrays nums : %p\n", &nums)
fmt.Println(nums)
incrByPtr(&nums)
fmt.Println(nums)
}
func incr(nums [3]int) {
fmt.Printf("incr nums : %p\n", &nums)
for i := range nums {
nums[i]++
fmt.Printf("incr.nums[%d] : %p\n", i, &nums[i])
}
}
func incrByPtr(nums *[3]int) {
for i := range nums {
nums[i]++
// (*nums)[i]++
}
}

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,57 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
in := bufio.NewScanner(os.Stdin)
p := newParser()
for in.Scan() {
// dom, err := parse(p, in.Text())
// if err != nil {
// fmt.Println(err)
// return
// }
// p = push(p, dom)
p = add(p, in.Text())
}
summarize(p)
dumpErrs(in.Err(), err(p))
}
// funcs not always need to be reused.
// here, it tells about what it does: it summarizes the parsing result.
func summarize(p parser) {
// Print the visits per domain
for _, d := range p.domains {
vis := p.sum[d.name]
fmt.Printf("%-25s -> %d\n", d.name, vis)
}
// Print the total visits for all domains
fmt.Printf("\n%-25s -> %d\n", "TOTAL", p.total)
}
// this variadic func simplifies the multiple error handling
func dumpErrs(errs ...error) {
for _, err := range errs {
if err != nil {
fmt.Printf("> Err: %s\n", err)
}
}
}

View File

@ -0,0 +1,85 @@
package main
import (
"fmt"
"strconv"
"strings"
)
// domain represents a domain log record
type domain struct {
name string
visits int
}
// parser parses a log file and provides an iterator to iterate upon the domains
//
// the parser struct is carefully crafted to be usable using its zero values except the map field.
type parser struct {
sum map[string]int // visits per unique domain
domains []domain // unique domain names
total int // total visits to all domains
lines int // number of parsed lines (for the error messages)
err error // saves the last error occurred
}
// newParser creates and returns a new parser.
func newParser() parser {
return parser{sum: make(map[string]int)}
}
func add(p parser, line string) parser {
// if there was a previous error do not add
if p.err != nil {
return p
}
dom, err := parse(p, line)
// store only the last error
if err != nil {
p.err = err
return p
}
return push(p, dom)
}
// error returns the last error occurred
func err(p parser) error {
return p.err
}
// parse parses the given text and returns a domain struct
func parse(p parser, line string) (dom domain, err error) {
p.lines++ // increase the parsed line counter (only write is here)
fields := strings.Fields(line)
if len(fields) != 2 {
err = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
return
}
name, visits := fields[0], fields[1]
n, err := strconv.Atoi(visits)
if n < 0 || err != nil {
err = fmt.Errorf("wrong input: %q (line #%d)", visits, p.lines)
return
}
return domain{name: name, visits: n}, nil
}
// push pushes the given domain to the internal list of domains.
// it also increases the total visits for all the domains.
func push(p parser, d domain) parser {
// collect the unique domains
if _, ok := p.sum[d.name]; !ok {
p.domains = append(p.domains, d)
}
p.sum[d.name] += d.visits
p.total += d.visits
return p
}

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,56 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
in := bufio.NewScanner(os.Stdin)
p := newParser()
for in.Scan() {
// dom, err := parse(p, in.Text())
// if err != nil {
// fmt.Println(err)
// return
// }
// p = push(p, dom)
add(p, in.Text())
}
summarize(p)
dumpErrs(in.Err(), err(p))
}
// funcs not always need to be reused.
// here, it tells about what it does: it summarizes the parsing result.
func summarize(p *parser) {
// multiple iterators can be created. each one remembers the last
// read domain record.
next, cur := iterator(p)
for next() {
dom := cur()
fmt.Printf("%-25s -> %d\n", dom.name, dom.visits)
}
fmt.Printf("\n%-25s -> %d\n", "TOTAL", p.total)
}
// this variadic func simplifies the multiple error handling
func dumpErrs(errs ...error) {
for _, err := range errs {
if err != nil {
fmt.Printf("> Err: %s\n", err)
}
}
}

View File

@ -0,0 +1,109 @@
package main
import (
"fmt"
"strconv"
"strings"
)
// domain represents a domain log record
type domain struct {
name string
visits int
}
// parser parses a log file and provides an iterator to iterate upon the domains
//
// the parser struct is carefully crafted to be usable using its zero values except the map field
type parser struct {
sum map[string]int // visits per unique domain
domains []domain // unique domain names
total int // total visits to all domains
lines int // number of parsed lines (for the error messages)
err error // saves the last error occurred
}
// newParser creates and returns a new parser.
func newParser() *parser {
return &parser{sum: make(map[string]int)}
}
// add parses the given line and saves the result to the internal list of
// domains. it doesn't add the record when the parsing fails.
func add(p *parser, line string) {
// if there was a previous error do not add
if p.err != nil {
return
}
dom, err := parse(p, line)
// store only the last error
if err != nil {
p.err = err
return
}
push(p, dom)
}
// iterator returns two functions for iterating over domains.
// next = returns true when there are more domains to iterate on.
// cur = returns the current domain
func iterator(p *parser) (next func() bool, cur func() domain) {
// remember the last received line
var last int
next = func() bool {
defer func() { last++ }()
return len(p.domains) > last
}
cur = func() domain {
d := p.domains[last-1]
vis := p.sum[d.name]
// return a copy so the caller cannot change it
return domain{name: d.name, visits: vis}
}
return
}
// error returns the last error occurred
func err(p *parser) error {
return p.err
}
// parse parses the given text and returns a domain struct
func parse(p *parser, line string) (dom domain, err error) {
p.lines++ // increase the parsed line counter (only write is here)
fields := strings.Fields(line)
if len(fields) != 2 {
err = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
return
}
name, visits := fields[0], fields[1]
n, err := strconv.Atoi(visits)
if n < 0 || err != nil {
err = fmt.Errorf("wrong input: %q (line #%d)", visits, p.lines)
return
}
return domain{name: name, visits: n}, nil
}
// push pushes the given domain to the internal list of domains.
// it also increases the total visits for all the domains.
func push(p *parser, d domain) {
// collect the unique domains
if _, ok := p.sum[d.name]; !ok {
p.domains = append(p.domains, d)
}
p.sum[d.name] += d.visits
p.total += d.visits
}

View File

@ -1,147 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import "fmt"
func main() {
// #1: Let's say you want to print a message three times like so.
// fmt.Println("hello gopher!")
// fmt.Println("hello gopher!")
// fmt.Println("hello gopher!")
// It works. However, when you want to do the same thing over and over again, it's better to use a function. Functions allow us to reuse the same block of code over and over again.
// For example, instead, let's say there is a function that prints the same message. Let's call it three times.
greet()
greet()
greet()
// #4: As you can see, it prints the same message three times because I've called the function three times. The benefit of using a function here is that I don't have to duplicate the code inside the function, and I can change it in one place like so (see #4B).
// #5: Now, let's say I want to print different messages like so.
greetWith("i'm bond. james bond.")
greetWith("i'm gopher. lovely gopher.")
// greetWith()
// #6B: BTW, if a function expects a parameter, I cannot call it without an argument like so. A parameter is a definition of what a function expects. An argument is the actual data that you send to a function. Here, the string value is an argument, it's a real value. But here, it's just a parameter declaration.
// #7: Now it prints different messages. You can pass and call this function with any string value. However, as you know, you cannot call it with other types like so.
// greetWith(42)
// Doing so is an error because the function only accepts a string.
// #8: Now, let's say I want to negate an integer value. For example, when I give it 100, it's going to give me -100.
n := negate(100)
fmt.Printf("negate(%d) = %d\n", 100, n)
// #10: As you can see, the negate function returns -100.
// #11: I can also pass multiple inputs to a function like so.
// Here, this function is going to multiply the given numbers and it will return a float64 number.
f := multiply(10, 20)
fmt.Printf("%d * %d = %g\n", 10, 20, f)
// #13: Now, let's take a look at a function that returns multiple values.
// I'm going to give it two numbers, and it's going to divide them, it's also going to return back an error if it cannot divide the numbers like so.
n, err := divide(10, 5)
// So, I'm going to the handle error as usual.
if err != nil {
fmt.Println(err)
// As you can see, here, this time, I'm returning from the main function. The main function is running the whole show. It orchestrates the other functions. So, when I return from the main function your program will terminate, or in other words, it will quit.
//
// BTW note that, here, I don't have to provide any arguments to the return statement because the main function doesn't return anything. As you can see, it doesn't declare any result parameters.
return
}
// If there isn't an error, I'm going to print the result like so.
fmt.Printf("%d / %d = %d\n", 20, 0, n)
// #15: As you can see, the divide function prints an error, and the program terminates because the main function returns. So, it doesn't execute the rest of the statements.
//
// Let me change the arguments so that the divide function can divide the numbers without any error.
// divide(10, 5)
//
// As you can see, this time, it prints the result of the division.
// #16B: Let me call it from here, with an empty string argument.
greetWith("")
}
// #2: Of course, the greet function doesn't exist yet, so let's declare it.
// It looks like the main function, however, its name is different, and it doesn't get called automatically, you need to call it by yourself. That's why I need to call it here [above].
//
// Inside the function, I'm going to print the hello message like so.
func greet() {
fmt.Println("hello gopher!")
// #4B: Now, it prints a different message. However, nothing interesting here, so let's continue :)
// fmt.Println("hello there!")
}
// #3: BTW, every declared function occupies the same name space of its package. I mean, you cannot redeclare a function with the same name of an existing function. So, there can be only one function within the same package with the same name. Also note that, Go doesn't support function overloading if you're wondering about it.
// func greet() {
// fmt.Println(hello)
// }
// #6: This time, I'm going to name the function greetWith. Here, inside the parentheses, I'm going to type the input parameter that the function is expecting. It expects only a single string parameter: message.
//
// Inside the function body, I'm going to print the given message like so.
func greetWith(message string) {
// #16: BTW, I don't have to return from this function as well because it doesn't declare a result value.
// However, if I want to, I can use the return statement in this function as well.
// Let's say I want to return from this function when it's called with an empty argument like so.
if message == "" {
// If so, I'm going to print the default message then I'm going to terminate the function.
fmt.Println("i can greet!")
return
}
fmt.Println(message)
// #16C: As you can see, when I call it without any arguments, it prints the default message instead.
}
// #9: To do that, I'm going to return an int value so the main function can print it.
// It's better for a function to have a single responsibility. Here, it only needs to negate the number, it's not responsible from printing it. So the caller of this function can use the returned data however it wants.
func negate(num int) int {
// The return statement returns a value to the calling function. Here, I'm going to return the number by negating it like so.
//
// As you can see, I can use an expression next to a return statement. Here, it returns the result of this expression.
return -num
// BTW, here, I can only return an int value because the function declares that it returns an int. For example, I cannot return a string value.
// return "nope"
}
// #12: So here, I'm going to declare the multiply function, and I'm going to declare it with two parameters. And lastly, I'm going to return a float64 value.
// As you can see, I can use the serial declaration, I could also have declared it like so:
// multiply(a float64, b float64)
// It's the same thing.
func multiply(a, b float64) float64 {
// Now, I'm going to multiply the given arguments and I'm going to return the result of the expression like so.
return float64(a) * b
}
// #14: OK, now let's declare the divide function.
// It accepts two int parameters, and returns two values like so.
//
// As you can see, when you return multiple values, you need to separate them with a comma, and you need to put them inside the parentheses. You can return more than two result values, but usually, we return two result values for making the function easy to work with.
func divide(a, b int) (int, error) {
// Inside the function, I'm going to check for the division by zero error. To do that I'm going to check whether the b is zero or not.
if b == 0 {
// If so, I'm going to return two values from the function.
// First, I'm going to return 0 because it's the zero value of an int type.
// I could have returned any other value as well, but idiomatically, it's better to return a zero value.
//
// Then, I'm going to return an error value using the Errorf function like so. This function is just like the Printf function, the only difference is that, instead of printing the result to the console, it returns an error value with the given message.
return 0, fmt.Errorf("error: divide by zero: %d/%d", a, b)
}
// OK, if the b argument is not zero, the execution will continue from here. So here, I'm going to divide the numbers, and as the second result value, I'm going to return nil because that is the zero value for the error type because the error type is an interface.
return a / b, nil
}

View File

@ -1,95 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
)
// #4: BTW, I can also use a package variable.
// Here, this variable belongs to the main package.
// So, any function inside the main package can see it.
//
// REF: http://wiki.c2.com/?GlobalVariablesAreBad
var even = 16
func main() {
// #1C: Let me declare a variable in the main function.
number := 1
// Now, I'm going to call the function with the variable.
incr(number)
fmt.Println("main.number :", number)
// As you can see, it prints 1 instead of 2. Why?
// It's because, Go is a pass-by-value language. So, when you pass an argument to a function, it gets copied.
// #1E: For example, I cannot print it here. It isn't available here because it's only in the scope of the incr function.
// fmt.Println("Inside main:", num)
// #2: The name of the incr function's input value is num.
// So, what would happen if I would declare a variable with the same name in the main function, and pass it to the incr function like so?
num := 10
incr(num)
fmt.Println("main.num :", num)
// As you can see, it doesn't matter whether the variable has the same name or not. There are two num variables with the same name but they are in different scopes. Inside the incr function, the num variable is a different variable even though the main function also has a variable with the same name.
// #3: So, how can you change the number in a function?
// Well, you can return a value from the function.
// This time, I'm using a function that decrements the given number.
num = 5
num = decr(num)
fmt.Println("main.num :", num)
// #3C: As you can see, this time, it has decremented the number.
// Here, I've simply got a copy of the number from the decr function.
// So, it's still not the decr function's local variable.
// #4C: Let me call the new function here like so.
square()
fmt.Println("even :", even)
// As you can see, this time the main function sees the change.
// It's because, as I've said, the even variable belongs to the main package, any code inside the main package can access it. However, doing so is not good because anyone can change it.
// #4E: Now, check out the result, it is 0! This is why pass-by-value is a good thing because it isolates the local variables of a function from another one. So the other functions cannot change the same data.
}
// #1: Let's say I want to increase the given number inside a function.
// So, I'm going to declare a function to do so.
// It accepts an int value, and it doesn't return anything.
func incr(num int) {
// #1D: Here, it receives the number value and then it declares a hidden variable behind the scenes like so.
// var num int
//
// This variable is local only to the incr function. So the other functions cannot see it from the outside of this function.
// #1F: The main function, passes 1 to this function. So, after declaring the hidden variable here, Go sets it to the given argument like so.
// num = 1
//
// And then, this statement increments the local copy of the variable.
// #1B: Here, I'm going to increase the number.
num++
// #1G: So, if I print it from here, it's going to say: 2.
fmt.Println("incr.num :", num)
// It prints 2 because the variable is a copy of the number variable.
}
// #3B: Let me also declare the function.
// It gets an int as an input value.
// And it decrements and returns the value.
func decr(num int) int {
// #4D: Let's say, for some weird reason, the decr function secretly changes the even variable. In a large code base this can easily go unnoticed.
even = 0
return num - 1
}
// #4B: Let me declare a function that squares this number.
// This time, this function doesn't accept or return any values because it operates on the package level variable.
func square() {
even *= even
}

View File

@ -1,65 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
)
func main() {
// As you've learned before Go is a pass-by-value programming language. So, when you assign a variable to another one, or pass it to a function, it gets copied.
// #1: Let's take a look at an example.
// Let's say you have an int variable.
// You want a function to increase the number.
number := 1
// In that case, you need to use a pointer because a pointer can send the memory location of the variable to the function, so the function can change the value directly on the memory.
//
// For example, let me pass the memory address of the number to the function like so.
//
// Remember: Ampersand sign here returns the memory location of the given variable.
incr(&number)
// Let me print the variable.
fmt.Println("&main.number :", number)
// #1C: Let's check it out.
// As you can see, now the number has changed to 2.
// The function could increment the number because it can directly access to the value of the variable by using its memory address.
// If you look at the memory address of the number variable, you will see that the function sees the same address, let me show you.
//
// Let me print the address of the number variable like so.
// Every pointer stores a memory location value.
// So the %p verb prints the address that a pointer stores.
fmt.Printf("&main.number : %p\n", &number)
}
// #1B: Let me also declare the function like so.
// This time, it accepts an int pointer.
// When you put an asterisk sign in front of a type, it becomes a pointer.
// Every type comes with its own pointer type like so.
// This is an int pointer because it has an asterisk in front of the int type. So, this pointer can only store the memory address of an int value.
func incr(num *int) {
// Inside the function I'm going to change the num variable by deferencing it like so, then I'm going to increase it as usual.
*num++
// #1D: Let me also print the memory address that the num pointer stores.
// Remember: num here is a pointer variable, it stores a memory address of an int value.
fmt.Printf("incr.number : %p\n", num)
// As you can see, the main function and the incr function use the same variable. They both are looking at the same memory location. That's why this function can change the value.
// However, if I print the memory address of the local num variable, it will print a different address, let me show you.
fmt.Printf("&incr.number : %p\n", &num)
// As you can see, the memory address of the local num variable is different than the memory address of this variable. It's because, Go is a pass-by-value language. So, it even copies the pointer variables. So, the local num pointer variable is a new variable inside this function. However, it stores the same address of the number variable of main function.
// In Go, everything is passed by value, even pointers, however, when the functions knows the memory address of a variable, it can change it directly. Otherwise it cannot change it because the variable belongs to the local scope of the function.
}

View File

@ -1,12 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
func main() {
}

View File

@ -1,98 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
)
func main() {
// #1: Go is a pass-by-value programming language. So, when you assign a variable to another one, or pass it to a function, it gets copied. Let me show you how it work in the context of the functions.
// #1C: Let me declare a variable.
number := 1
// Now, I'm going to call the function with the variable.
incr(number)
// Let me print the variable here.
fmt.Println("main.number :", number)
// As you can see, it prints 1 instead of 2. Why?
// It's because, as I've said, Go is a pass-by-value programming language.
// #1E: For example, I cannot print it here. It isn't available here because the num is local to the incr function. It's in the scope of the incr function. If you don't remember the scopes, please check out the earlier scope lectures.
// fmt.Println("Inside main:", num)
// #2: So what if you want to change the value in the function?
// In that case, you need to use a pointer because a pointer can send the memory location of the variable to the function, so the function can change the value directly on the memory.
//
// For example, let me pass the address of the number to another function like so. Ptr is short for pointer, we use it a lot.
//
// Ampersand sign here returns the memory location of the given variable.
incrByPtr(&number)
// Let me print the variable.
fmt.Println("&main.number :", number)
// #2C: Let's check it out.
// As you can see, now the number has changed to 2.
// The function could increment the number because it can directly access to the value of the variable by using its memory address.
// If you look at the memory address of the number variable, you will see that the function sees the same address, let me show you.
//
// Let me print the address of the number variable like so.
// Every pointer stores a memory location value.
// So the %p verb prints the address that a pointer stores.
fmt.Printf("&main.number : %p\n", &number)
}
// #1B:
// Let's say I want to increase the given number inside the function.
//
// So, I'm going to declare a function named Incr to do so.
// It accepts an int value, and it doesn't return anything.
func incr(num int) {
// #1D: Here, it receives the num and then it declares a variable behind the scenes like so.
// var num int
// This variable is local to the incr function. The other functions cannot see this variable from the outside of this function.
// #1F: The main function, passes 1 to this function. So, after declaring the hidden variable here, Go sets it to the given argument like so.
// num = 1
//
// And then, this statement works and it increments the num variable. However, it increases its own local copy of the num variable.
// #1B: Inside the function, I'm going to try to increase the given number like so.
num++
// #1G: So, if I print it from here, it's going to say: 2.
fmt.Println("incr.num :", num)
// As you can see, it prints 2 because it gets copied here.
}
// #2B: Let me also declare the function like so.
// This time, it accepts an int pointer.
// When you put an asterisk sign in front of a type, it becomes a pointer.
// Every type comes with its own pointer type like so.
// This is an int pointer because it has an asterisk in front of the int type. So, this pointer can only store the memory address of an int value.
func incrByPtr(num *int) {
// Inside the function I'm going to change the num variable by deferencing it like so, then I'm going to increase it as usual.
*num++
// #2D: Let me also print the memory address that the num pointer stores.
// Remember: num here is a pointer variable, it stores a memory address of an int value.
fmt.Printf("incrByPtr.number : %p\n", num)
// As you can see, the main function and the incrByPtr function use the same variable. They both are looking at the same memory location. That's why this function can change the value.
// However, if I print the memory address of the local num variable, it will print a different address, let me show you.
fmt.Printf("&incrByPtr.number: %p\n", &num)
// As you can see, the memory address of the local num variable is different than the memory address of this variable. It's because, Go is a pass-by-value language. So, it even copies the pointer variables. So, the local num pointer variable is a new variable inside this function. However, it stores the same address of the number variable of main function.
// Don't worry, I'm going to talk about pointers in detail soon. For now, just know that, in Go, everything is passed by value, even pointers, however, when the functions knows the memory address of a variable, it can change it directly. Otherwise it cannot change it because the variable belongs to the local scope of the function.
// Pass by value is a very good mechanism because it isolates the variables of a function from another one.
}

View File

@ -1,12 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
func main() {
}

View File

@ -1,12 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
func main() {
}

View File

@ -1,12 +0,0 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
func main() {
}