LoginSignup
0
1

More than 5 years have passed since last update.

golangでHello Worldをやってみる

Last updated at Posted at 2017-04-02

golangのHello Worldをしてみる。

前提

  • ver 1.8

実践

hello.go
package main

import "fmt"

func main() {
    fmt.Println("hello golang")
}

はい。

雑なHelloWorldの説明

hello.goというファイルを作る。
package宣言する。importを指定する。main関数でfmtのPrintln関数を呼び出す。

import

標準出力をするためにfmtをimportする。

src/fmtディレクトリ以下のgoファイルのPublicなものが使えるようになる。

$pwd
/usr/local/Cellar/go/1.8/libexec/src/fmt
$ ls
doc.go                  fmt_test.go             print.go                scan_test.go
export_test.go          format.go               scan.go                 stringer_test.go

この中の_test.goとなっているものは外からは呼び出せない。
fmt.Printlnはfmtパッケージ内のPrintln関数呼び出しなので、fmtの中からPrintln関数を持つファイルを探す。
関数はJavaみたいにclassとかに属すのではなくて、多分パッケージに属する。トップレベル関数って感じがする。

名前的にprint.goっぽいですね。実際、IDEからジャンプしてみるとそうでした。

print.go

  • println
print.go
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}

Println関数は、intefaceを可変に受け取り、intとerrorを返す関数。
内部ではFprintlnを呼び出す。Fprintlnにはstandard out(標準出力)と受け取った引数をそのまま渡している。

  • FPrintln
print.go
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
    p := newPrinter()
    p.doPrint(a)
    n, err = w.Write(p.buf)
    p.free()
    return
}

FprintではPrinterの生成、Printerによる出力処理、io.Writer(標準出力)でのwriteを行ったあと、Printerの開放を行う。最後にreturnとだけあるが、戻り値が無いわけではなく、戻り値の変数名として指定したものと関数スコープ内で利用している変数名の一致しているものが返されているっぽい。
従ってここでは、n,errという変数がw.Write(p.buf)の戻り値であり、このFprint自体の戻り値となる。

  • newPrinter

Fprintln内で呼び出されているnewPrinter関数。先頭が小文字なのでprivateな関数。

print.go
var ppFree = sync.Pool{
    New: func() interface{} { return new(pp) },
}

func newPrinter() *pp {
    p := ppFree.Get().(*pp)
    p.panicking = false
    p.erroring = false
    p.fmt.init(&p.buf)
    return p
}

戻り値はppというstructのポインタ。

ppというstructは以下。

print.go
// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.
type pp struct {
    buf buffer

    // arg holds the current item, as an interface{}.
    arg interface{}

    // value is used instead of arg for reflect values.
    value reflect.Value

    // fmt is used to format basic items such as integers or strings.
    fmt fmt

    // reordered records whether the format string used argument reordering.
    reordered bool
    // goodArgNum records whether the most recent reordering directive was valid.
    goodArgNum bool
    // panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
    panicking bool
    // erroring is set when printing an error string to guard against calling handleMethods.
    erroring bool
}

ppFreeは変数でPoolというstructに対して関数を指定したもの。
new関数はbuiltinのもの。

builtin.go
// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly
// allocated zero value of that type.
func new(Type) *Type

ppFreeでppのためのnew領域を確保している(メモリアロケート)。
ここまでがnewPrinterの1行目。
2〜3行目ではppというstructのメンバの設定をしている。

  • doPrintln
print.go
// doPrintln is like doPrint but always adds a space between arguments
// and a newline after the last argument.
func (p *pp) doPrintln(a []interface{}) {
    for argNum, arg := range a {
        if argNum > 0 {
            p.buf.WriteByte(' ')
        }
        p.printArg(arg, 'v')
    }
    p.buf.WriteByte('\n')
}

引数分ループし、ppというstructの持つバッファーに対して書き込み。
このdoPrintln関数のようにfuncと関数名の間に (p *pp) などとすることで関数のレシーバーを指定することが出来る。
要は、pp.doPrintlnで呼び出せるようになる。
printArgも追ってみたけど、結構プリミティブな感じになっていた。printArgでは、golangの持つ型ごとにパターンマッチしてfmtを変えてprintしている。

print.go
func (p *pp) printArg(arg interface{}, verb rune) {
    p.arg = arg
    p.value = reflect.Value{}

    if arg == nil {
        switch verb {
        case 'T', 'v':
            p.fmt.padString(nilAngleString)
        default:
            p.badVerb(verb)
        }
        return
    }

    // Special processing considerations.
    // %T (the value's type) and %p (its address) are special; we always do them first.
    switch verb {
    case 'T':
        p.fmt.fmt_s(reflect.TypeOf(arg).String())
        return
    case 'p':
        p.fmtPointer(reflect.ValueOf(arg), 'p')
        return
    }

    // Some types can be done without reflection.
    switch f := arg.(type) {
    case bool:
        p.fmtBool(f, verb)
    case float32:
        p.fmtFloat(float64(f), 32, verb)
    case float64:
        p.fmtFloat(f, 64, verb)
    case complex64:
        p.fmtComplex(complex128(f), 64, verb)
    case complex128:
        p.fmtComplex(f, 128, verb)
    case int:
        p.fmtInteger(uint64(f), signed, verb)
    case int8:
        p.fmtInteger(uint64(f), signed, verb)
    case int16:
        p.fmtInteger(uint64(f), signed, verb)
    case int32:
        p.fmtInteger(uint64(f), signed, verb)
    case int64:
        p.fmtInteger(uint64(f), signed, verb)
    case uint:
        p.fmtInteger(uint64(f), unsigned, verb)
    case uint8:
        p.fmtInteger(uint64(f), unsigned, verb)
    case uint16:
        p.fmtInteger(uint64(f), unsigned, verb)
    case uint32:
        p.fmtInteger(uint64(f), unsigned, verb)
    case uint64:
        p.fmtInteger(f, unsigned, verb)
    case uintptr:
        p.fmtInteger(uint64(f), unsigned, verb)
    case string:
        p.fmtString(f, verb)
    case []byte:
        p.fmtBytes(f, verb, "[]byte")
    case reflect.Value:
        // Handle extractable values with special methods
        // since printValue does not handle them at depth 0.
        if f.IsValid() && f.CanInterface() {
            p.arg = f.Interface()
            if p.handleMethods(verb) {
                return
            }
        }
        p.printValue(f, verb, 0)
    default:
        // If the type is not simple, it might have methods.
        if !p.handleMethods(verb) {
            // Need to use reflection, since the type had no
            // interface methods that could be used for formatting.
            p.printValue(reflect.ValueOf(f), verb, 0)
        }
    }

ちなみにruneってなんだ?というと

builtin.go
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune rune

らしいです。

  • free
print.go
// free saves used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
    p.buf = p.buf[:0]
    p.arg = nil
    p.value = reflect.Value{}
    ppFree.Put(p)
}

freeはppのメモリ領域の開放。

気になったところ

builtin.goとは

Package builtin provides documentation for Go's >predeclared identifiers.
The items documented here are not actually in package >builtin but their descriptions here allow godoc to present documentation for the language's special identifiers.

builtinパッケージはGoの事前定義された識別子らしい。

なぜ突然reflectが現れるか

reflect.Value{}が出てきて唐突に感じたけど、reflectというのにとらわれず、reflectパッケージ内のValueというstructを使っているだけだと思えばまぁ良いのかなと思った。
Valueの説明は以下。

// A Value can be used concurrently by multiple >goroutines provided that
// the underlying Go value can be used concurrently for the equivalent

Valueはconcurrentな処理も考慮して作られているということらしい。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1