Syntax of a function

I am looking into the chapter Writing Web Application of the Golang docs, and found this syntax of a function:

func (p *Page) save() error {
    filename := p.Title + ".txt"
    return os.WriteFile(filename, p.Body, 0600)
}

And from the docs... This is a method named save that takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type error.

  1. What is the difference between declaring the function like this func save(p *Page) error{}? What is the difference between a receiver and a function parameter?
  2. Why is it returning a value of type error, when I see it is returning a function from the os package?

Thank you in advance, may be a dumb question but I'm kinda new to Golang,


  1. What is the difference between declaring the function like this func save(p *Page) error{}? What is the difference between a receiver and a function parameter?

These are functionally identical, this is what Go does underwater when compiling. But there are a few semantic differences:

  • The largest difference is that you would call func (p *Page) save() error like somePage.save() and func save(p *Page) error as save(somePage).
  • Documentation generated by go.dev will list it as a function in the package, not as method for Page (assuming it was an exported function).
  • When declaring a func like func save(p *Page) error will not make Page implement an interface like interface{ save() } where as the method will.
  • Go will convert between pointers and values for you when calling a method, but for functions you must always pass the correct param type yourself. For example:
type Page struct {
    Field string
}

func (p *Page) PtrString() string {
    return p.Field
}

func (p Page) String() string {
    return p.Field
}

func PageString(page Page) string {
    return page.Field
}

func PagePtrString(page *Page) string {
    return page.Field
}

func main() {
    p := Page{Field: "Hello world"}

    // Both work
    fmt.Println(p.String())
    fmt.Println(p.PtrString()) // This passes a pointer implicitly

    // This works
    fmt.Println(PageString(p))

    // This doesn't compile
    fmt.Println(PagePtrString(p)) // cannot use p (type Page) as type *Page in argument to PagePtrString

    // But this does, you have to specify you want to pass a pointer
    fmt.Println(PagePtrString(&p))
}

Here is a link with more details about the difference between pointer and value receivers.

  1. Why is it returning a value of type error, when I see it is returning a function from the os package?

It doesn't return the function itself, it calls it and returns the return value of os.WriteFile, which is error