Go/コードギャラリー

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

このコードギャラリーは、さまざまなGoの機能やパターン、ベストプラクティスを示すためのサンプルコード集です。

エラトステネスの篩[編集]

package main

import (
	"fmt"
)

func eratosthenes(n int) {
	sieve := make([]bool, n+1)
	sieve[0] = false
	sieve[1] = false
	for i := 2; i <= n; i++ {
		sieve[i] = true
	}

	for i := 2; i <= n; i++ {
		if sieve[i] {
			fmt.Println(i)

			for j := i * 2; j <= n; j += i {
				sieve[j] = false
			}
		}
	}
}

func main() {
	eratosthenes(100)
}

このGoのコードは、エラトステネスの篩を使って与えられた上限値以下の素数を見つけるものです。エラトステネスの篩は、素数を見つけるための古典的なアルゴリズムで、与えられた範囲内の素数を効率的に見つけることができます。

コードの主なポイントは次のとおりです:

  1. eratosthenes 関数は、与えられた上限値 n 以下の素数を見つけるための関数です。
  2. sieve というブール型のスライスを作成し、初期値はすべて true に設定されます。このスライスは素数かどうかを示すために使用されます。
  3. sieve[0]sieve[1] は素数ではないため、それぞれ false に設定されます。
  4. i が2から始まり、n までループします。もし sieve[i]true(素数である)場合は、i を素数として出力し、その後の倍数を false にします。これにより、素数の倍数は素数ではないとマークされます。
  5. 内側のループでは、i の倍数をすべて篩い落とすため、ji の倍数として増やしながら sieve[j]false にしています。
  6. main 関数では、eratosthenes 関数を呼び出して上限値が100以下の素数を見つけ、それを出力します。

このコードでは、エラトステネスの篩を用いて効率的に素数を見つける方法が示されています。

最大公約数と最小公倍数[編集]

package main

import (
	"fmt"
)

func reduce(operation func(int, int) int, values []int) int {
	result := values[0]
	for _, value := range values[1:] {
		result = operation(result, value)
	}
	return result
}

func gcd2(m, n int) int {
	if n == 0 {
		return m
	}
	return gcd2(n, m%n)
}

func gcd(ints ...int) int {
	return reduce(gcd2, ints)
}

func lcm2(m, n int) int {
	return m * n / gcd2(m, n)
}

func lcm(ints ...int) int {
	return reduce(lcm2, ints)
}

func main() {
	fmt.Printf("gcd2(30, 45) => %d\n", gcd2(30, 45))
	fmt.Printf("gcd(30, 72, 12) => %d\n", gcd(30, 72, 12))
	fmt.Printf("lcm2(30, 72) => %d\n", lcm2(30, 72))
	fmt.Printf("lcm(30, 42, 72) => %d\n", lcm(30, 42, 72))
}

このGoのコードは、最大公約数(GCD)と最小公倍数(LCM)を計算する関数を提供しています。これらの関数は、与えられた整数の配列を処理し、それぞれの計算を行います。

  • reduce関数は、2つの引数を取り、指定された二項演算(operation)をスライスの要素に対して適用するためのものです。
  • resultは初期値として最初の要素(values[0])を取り、それ以降の要素に対して operation を適用していきます。
  • スライスの範囲演算子 values[1:] を使用して、最初の要素を除いた残りの要素に対して操作を行います。

二分法[編集]

二分法

package main

import (
	"fmt"
	"math"
)

func bisection(low, high float64, f func(float64) float64) float64 {
	x := (low + high) / 2
	fx := f(x)

	if math.Abs(fx) < 1.0e-10 {
		return x
	}

	if fx < 0.0 {
		low = x
	} else {
		high = x
	}

	return bisection(low, high, f)
}

func main() {
	result1 := bisection(0, 3, func(x float64) float64 {
		return x - 1
	})
	fmt.Println(result1)

	result2 := bisection(0, 3, func(x float64) float64 {
		return x*x - 1
	})
	fmt.Println(result2)
}
旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を Go に移植しました。

このGoのコードは、2分法を用いて与えられた関数の数値解を求める方法を示しています。

bisection 関数[編集]

  • bisection 関数は、与えられた上限値と下限値の範囲内で数値解を見つけるためのものです。
  • lowhigh は、数値解を探す範囲を示します。
  • f は、数値解を求めたい関数です。
  • x := (low + high) / 2 で、範囲の中間点を計算します。
  • fx := f(x) で、関数 f を中間点 x に適用し、その結果を fx に代入します。
  • math.Abs(fx) < 1.0e-10 は、絶対値が非常に小さい値となった場合、つまり数値解が見つかった場合の条件です。この場合、x を返して探索を終了します。
  • fx < 0.0 の場合は、low の範囲を x に設定し、それ以外の場合は high の範囲を x に設定します。これにより、次の探索範囲を絞り込んでいきます。
  • 最後に、絞り込まれた新しい範囲で再帰的に bisection 関数を呼び出します。

main 関数[編集]

  • main 関数では、bisection 関数を使用して数値解を求めます。
  • まず、x - 1 という関数に対して2分法を適用し、数値解を見つけます。次に、x^2 - 1 という関数に対しても同様の手順で数値解を見つけます。
  • それぞれの数値解を出力しています。

このコードは、数値解を見つけるための2分法を実装し、与えられた関数に対して数値解を計算する方法を示しています。

構造体とメソッド[編集]

Goにクラスはありませんが、構造体がメソッドを持つことが出来ます。

package main

import "fmt"

// Hello 構造体
type Hello struct {
	s string // 挨拶文に含める文字列
}

// NewHello Hello構造体のコンストラクタ
func NewHello(s string) *Hello {
	if s == "" {
		s = "world" // デフォルト値を設定
	}
	return &Hello{s: s}
}

// ToString 挨拶文を文字列で表現するメソッド
func (h *Hello) ToString() string {
	return fmt.Sprintf("Hello %s!", h.s)
}

// Print 挨拶文を出力するメソッド
func (h *Hello) Print() {
	fmt.Println(h.s)
}

func main() {
	hello1 := NewHello("")
	fmt.Println(hello1.ToString())
	hello1.Print()

	hello2 := NewHello("my friend")
	fmt.Println(hello2.ToString())
	hello2.Print()

	fmt.Printf(`
Hello.constructor.name => Hello
hello1 => %+v
hello2.s => %s
`, hello1, hello2.s)
}

このGoのコードは、Hello 構造体を定義し、それに関連する関数とメソッドを使って挨拶文を扱う方法を示しています。

Hello 構造体と NewHello コンストラクタ[編集]

  • Hello 構造体は、挨拶文に含める文字列 s を持ちます。
  • NewHello 関数は、Hello 構造体のコンストラクタです。引数が空の場合はデフォルトで "world" を設定します。

ToString メソッド[編集]

  • ToString メソッドは、Hello 構造体のメソッドです。挨拶文を文字列で表現します。

Print メソッド[編集]

  • Print メソッドは、Hello 構造体のメソッドで、挨拶文を出力します。

main 関数[編集]

  • main 関数では、NewHello コンストラクタを使って2つの Hello インスタンスを作成します。
  • それぞれのインスタンスに対して ToString メソッドを呼び出し、挨拶文を表示します。
  • 同様に、Print メソッドを呼び出して挨拶文を出力します。
  • Printf 関数を使用して、コンストラクタの名前、hello1 の詳細情報、および hello2 の文字列を出力します。

このコードは、Go言語でクラスの代わりに構造体とメソッドを使用して、オブジェクト指向プログラミングの概念を模倣しています。それぞれのメソッドは、構造体のインスタンスに結びついており、そのインスタンスに対して操作を行います。

逆ポーランド記法の解析と評価[編集]

逆ポーランド記法は、数式の演算子を後置記法で表現する方法です。通常の中置記法では演算子がオペランドの間に置かれますが、逆ポーランド記法では演算子がオペランドの後ろに置かれます。これにより、括弧や演算子の優先順位を考える必要がなくなり、計算機で容易に評価できる形式になります。

例えば、中置記法での式 3 + 4 * 5 は、逆ポーランド記法では 3 4 5 * + と表現されます。この記法では、演算子が対象のオペランドに対して順番に適用されます。

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func evaluateExpression(expression string) (int, error) {
	tokens := strings.Fields(expression)
	stack := make([]int, 0)

	for _, token := range tokens {
		switch token {
		case "+", "-", "*", "/":
			if len(stack) < 2 {
				return 0, fmt.Errorf("invalid expression: not enough operands for %s operator", token)
			}
			operand2 := stack[len(stack)-1]
			operand1 := stack[len(stack)-2]
			stack = stack[:len(stack)-2]

			var result int
			switch token {
			case "+":
				result = operand1 + operand2
			case "-":
				result = operand1 - operand2
			case "*":
				result = operand1 * operand2
			case "/":
				if operand2 == 0 {
					return 0, fmt.Errorf("division by zero")
				}
				result = operand1 / operand2
			}
			stack = append(stack, result)
		default:
			num, err := strconv.Atoi(token)
			if err != nil {
				return 0, fmt.Errorf("invalid expression: %v is not a number", token)
			}
			stack = append(stack, num)
		}
	}

	if len(stack) != 1 {
		return 0, fmt.Errorf("invalid expression: too many operands or operators")
	}

	return stack[0], nil
}

func main() {
	expression := "5 3 2 * + 8 2 / -"
	result, err := evaluateExpression(expression)
	if err != nil {
		fmt.Println("Error:", err)
	} else {
		fmt.Println("Result:", result)
	}
}

このGoのコードは、逆ポーランド記法(逆ポーランド式、Postfix Notation)を使用して算術式を評価します。

evaluateExpression 関数[編集]

  • evaluateExpression 関数は、逆ポーランド記法の式を受け取り、計算結果とエラーを返す関数です。
  • 式をトークンに分割し、それぞれのトークンをスタックに積んでいきます。
  • 演算子を見つけた場合は、スタックから必要な数のオペランドを取り出して、演算を行います。その結果をスタックに戻します。
  • 数字を見つけた場合は、文字列から整数に変換してスタックに積みます。
  • 除算 (/) の際にゼロで割り算が発生しないように注意しています。

main 関数[編集]

  • main 関数では、evaluateExpression 関数を使用して、与えられた逆ポーランド記法の式を評価します。
  • "5 3 2 * + 8 2 / -" を評価し、結果を出力します。

このプログラムは、逆ポーランド記法を使用して四則演算を行う方法を示しています。それぞれの演算子や数値をトークンとして扱い、スタックを使用して計算を進めます。計算結果を正しく得るために、演算子とオペランドの関係性を考慮して処理しています。