エラー 編集

エラー(Errors) -- 宣言済みの型であるerrorは次のように定義されています[1]

 type error interface {
 	Error() string
 }

これは、エラー状態を表現するための従来のインターフェースで、nil値はエラーがないことを表します。例えば、ファイルからデータを読み取る関数が定義されているとします。

func Read(f *File, b []byte) (n int, err error)

ランタイム・パニック 編集

Goにおいて、配列の範囲外のインデックスを参照するなどの実行時エラーが発生した場合、ランタイム・パニック(Run-time panics)と呼ばれるエラーが発生します。このエラーは、ランタイムに発生するエラーであり、予期しない状況が発生したことを示しています。

ランタイム・パニックが発生した場合、プログラムは中断されます。この状況を回避するためには、プログラム内でエラー処理を実装する必要があります。ランタイム・パニックが発生した場合、組み込み関数 panic が呼び出され、実装で定義されたインタフェース型runtime.Error型のインタフェース値が生成されます。このエラーは、事前に宣言されたインタフェース型errorを満たします。

ランタイム・パニックは、Goのコンパイラによって検出できないエラーです。このため、ランタイム・パニックを回避するためには、コードを慎重にテストする必要があります。ランタイム・パニックが発生した場合、エラー値は不定であり、異なるランタイム・エラー条件を表すことがあります[2]

package runtime

type Error interface {
	error
	// そしておそらく他のメソッド
}

Goの例外処理 編集

Go言語では、エラーハンドリングや例外処理を行うために、error インターフェースを使います。一般的に、関数は error を返すことがあります。エラーが発生した場合、errornil でないことを確認し、適切な処理を行います。以下は、基本的な例です。

package main

import (
	"errors"
	"fmt"
)

func divide(x, y int) (result int, err error) {
	if y == 0 {
		err = errors.New("ゼロで割ることはできません")
		return
	}
	result = x / y
	return
}

func main() {
	result, err := divide(10, 2)
	if err != nil {
		fmt.Println("エラー:", err)
	} else {
		fmt.Println("結果:", result)
	}

	result, err = divide(10, 0)
	if err != nil {
		fmt.Println("エラー:", err)
	} else {
		fmt.Println("結果:", result)
	}
}

この例では、divide 関数は2つの引数を受け取り、割り算を行います。もしゼロで割ろうとした場合は、エラーを返します。main 関数では、divide を使って計算を行い、エラーがある場合はエラーメッセージを表示します。

Goでは、errornil であればエラーが発生していないことを示し、nil でなければエラーがあることを示します。このようにして、エラーハンドリングと例外処理を行います。

システム面での注意点 編集

システム面での注意点(System considerations)[3]

パッケージ unsafe 編集

組込みパッケージ unsafe は、コンパイラーに知られており、インポート・パス "unsafe"でアクセスでき、型システムに違反する操作を含む低レベルのプログラミングのための機能を提供します。unsafeを使用したパッケージは、手動で型安全性を吟味する必要があり、ポータブルではないかもしれません。パッケージは以下のインタフェースを提供します[4]

package unsafe

type ArbitraryType int // 任意のGo型の略語。実数型ではない。
type Pointer *ArbitraryType

func Alignof(variable ArbitraryType) uintptr
func Offsetof(selector ArbitraryType) uintptr
func Sizeof(variable ArbitraryType) uintptr

type IntegerType int // 整数型の略記で,実数型ではない
func Add(ptr Pointer, len IntegerType) Pointer 
func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType

Pointer はポインター型ですが、Pointer の値はdereferencedできません。基礎となる uintptr 型の任意のポインターまたは値は、基礎となる Pointer 型の型に変換することができ、その逆も可能です。Pointeruintptr の間の変換の効果は、実装で定義されます。

var f float64
bits = *(*uint64)(unsafe.Pointer(&f))

type ptr unsafe.Pointer
bits = *(*uint64)(ptr(&f))
 
var p ptr = nil

関数 Alignof および Sizeof は、任意の型の式 x を受け取り、あたかも var v = xv が宣言されたかのように、仮想変数 v のアラインメントまたはサイズをそれぞれ返します。

Offsetof 関数は、s または *s で示される構造体のフィールド f を示す(括弧で囲まれた)セレクタ s.fを受け取り、構造体のアドレスに対するフィールドのオフセットをバイト単位で返します。

f が埋め込みフィールドの場合は、構造体のフィールドを介してポインタの間接性なしに到達可能でなければなりません。

フィールド f を持つ構造体 s の場合。

uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))

コンピューター・アーキテクチャーでは、メモリー・アドレスを整列(aligned)することが要求される場合があります。つまり、変数のアドレスは、変数の型の整列を表す係数の倍数でなければなりません。関数 Alignof は、任意の型の変数を示す式を受け取り、(その型の)変数のアラインメントをバイト単位で返す。

変数 x の場合。

uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0

Alignof, Offsetof, Sizeof の呼び出しは、uintptr 型のコンパイル時定数式です。

関数 Add は、lenptr に追加し、更新されたポインター unsafe.Pointer(uintptr(ptr) + uintptr(len)) を返します。len 引数は、整数型または型付けされていない定数でなければなりません。定数の len 引数は int 型の値で表現できなければなりません。型付けされていない定数の場合は int 型になります。Pointer の有効な使用法に関する規則も適用されます。

関数 Slice は、基底となる配列が ptr で始まり、長さと容量が len であるスライスを返します。Slice(ptr, len) は以下と同じです。

(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]

ただし、特殊なケースとして、ptrnillen が0の場合、Slicenil を返します。

len 引数は整数型または型付けされていない定数でなければなりません。定数 len の引数は非負で、int型の値で表現できなければなりません。型付けされていない定数の場合は、int型が与えられます。実行時に len が負の値の場合、あるいは ptrnillen が 0 でない場合、ランタイム・パニックが発生します。

サイズとアライメントの保証 編集

サイズとアライメントの保証(Size and alignment guarantees) -- 数値型では、以下のサイズが保証されています[5]

バイト数
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16

以下のミニマムアライメント特性が保証されています。

  1. 任意の型の変数 x に対して。unsafe.Alignof(x)は最低でも1である。
  2. struct 型の変数 x の場合。unsafe.Alignof(x)は、xの各フィールドfの値unsafe.Alignof(x.f)のうち最大のもので、少なくとも1である。
  3. 配列型の変数 x の場合。unsafe.Alignof(x)は、配列の要素型の変数のアラインメントと同じになります。

構造体や配列型は、ゼロより大きなサイズを持つフィールド(または要素)を含まない場合、サイズがゼロになります。2つの異なるゼロサイズの変数が、メモリ上で同じアドレスを持つことがあります。

脚註 編集

  1. ^ “Errors¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Errors. 
  2. ^ “Run time panics¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Run_time_panics. 
  3. ^ “System considerations¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#System_considerations. 
  4. ^ “Package unsafe¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Package_unsafe. 
  5. ^ “Size and alignment guarantees¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Size_and_alignment_guarantees. 

参考文献 編集