GO Official Tutorial Note 1

Purpose

--Writing notes to catch up with GO language ――Since the formula is in English, proceed with Japanese localization + annotations (translation is Deepl)

Introduction

The site I'm referring to is the Wiki Tutorial listed in the GO Official. In this article, we will deal with the above URLs up to Getting Started and Data Structures. I think it's okay to just take a quick look at this page without doing a tutorial

Contents

First, create a directory

$ mkdir gowiki
$ cd gowiki

Create a file named wiki.go, open it in your favorite editor and add the following line:

wiki.go


package main

import (
	"fmt"
	"io/ioutil"
)

--fmt ... Reference Packages required to implement format I / O --io / ioutil ... Reference Easy input / output of files

In other words, you need two packages to input characters to a file with format I / O and upload it, I see!

Next, define to determine the data structure

Let's start by defining the data structure. A wiki consists of a series of interconnected pages, each with a title and body (page content). Here we define Page as a structure with two fields that represent the title and body.

There is only the file name wiki, and the intention is title + content = one page, so it's easy to understand.

wiki.go


type Page struct {
    Title string
    Body  []byte
}

type [] byte means "slice of bytes". The Body element is a [] byte, not a string. This is because it's the type you expect from your io library, as we'll see later.

It's related to the reason why I imported the two packages above.

The Page structure describes how page data is stored in memory. But what about persistent storage? You can deal with that by creating a save method on the Page.

wiki.go


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

The signature of this method looks like this: "This is a method named save that takes a pointer p to the Page as a receiver. It takes no parameters and returns an error-type value."

Here, for dynamically typed languages only, a sentence of `receives a pointer p to Page``? I think it will be (I was)

There was a Qiita article that explained when I looked it up.

A pointer variable is a variable that can be entered with an address in memory as a value.

So, in this example,

--The address of the information created by the save () method is in p --Currently, the information contained in p is title: p.Title, content: p.body

It is that!

And one more point Does not take a parameter and returns an error type value

Isn't an error returned if save is successful? I think there are people who think that. There is an explanation for that.

The> save method returns an error value because it is the return type of WriteFile (a standard library function that writes byte slices to a file). The save method returns an error value, allowing the application to handle any problems while writing the file. If all goes well, Page.save () will return nil (zero values for pointers, interfaces, and some other types).

If save is successful, nil is returned instead of error.

Next is the page loading function.

In addition to saving the page, you will want to load the page.

wiki.go


func loadPage(title string) *Page {
    filename := title + ".txt"
    body, _ := ioutil.ReadFile(filename)
    return &Page{Title: title, Body: body}
}

The loadPage function constructs a filename from the title parameter, loads the contents of the file into a new variable body, and returns a pointer to a Page literal constructed with the appropriate title and body values.

If you understand how pointers work, you can easily understand this. It just searches with the given title parameter and brings in the matching data.

But here body, _ := ioutil.ReadFile(filename) Hmm? _What?

There is also an explanation, so let's read it.

The function can return multiple values. The standard library function io.ReadFile returns [] bytes and an error. The loadPage has not yet handled the error. The "blank identifier" represented by the underscore (_) symbol is used to discard the return value of the error (essentially no value is assigned to anything).

In other words, _ is added to discard the returned error value. If you don't need it, why not make it so that it will not be returned?

Some people have asked the same question about this in About Underscore Variables (https://teratail.com/questions/58180). Due to the nature of the GO language, if you do not use the declared variable, a syntax error will occur, so it seems that there is an intention to omit the error if it does not definitely result in an error.

But is there any guarantee that there will be no errors? What if an error occurs? In the first place, it is delicate when people make that judgment. I think there are many people who think so.

rest assured. There is an explanation about it.

But what if ReadFile encounters an error? For example, the file may not exist. Don't ignore such errors. Now let's modify the function to return a Page and an error.

It will be the flow to modify the above source.

wiki.go


func loadPage(title string) (*Page, error) {
    filename := title + ".txt"
    body, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Title: title, Body: body}, nil
}

The caller of this function can now check the second parameter. Otherwise, you will get an error that the caller can handle.

Both problems are solved by checking the error with the if statement and adding nil to the return value.

This completes the source addition and enters the check.

At this point, you have a simple data structure and you can save to and read from a file. Let's write the main function to test what we wrote. You can compile and run it like this.

$ go build wiki.go
$ ./wiki
This is a sample Page.

If you run it and the message This is a sample Page. is displayed, it is successful.

Full text (copy and paste is OK)

wiki.go


package main

import (
	"fmt"
	"io/ioutil"
)

type Page struct {
	Title string
	Body  []byte
}

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

func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

func main() {
	p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
	p1.save()
	p2, _ := loadPage("TestPage")
	fmt.Println(string(p2.Body))
}

At the end

I posted it as a memo, so it looks like a scribble. Please comment if you have any!

Recommended Posts

GO Official Tutorial Note 1
Note about pointers (Go)
Django Girls Tutorial Note
Note
Note
Note
Try Django's official tutorial from scratch
A note about doing the Pyramid tutorial