システムに関する考慮事項

システムに関する考慮事項

unsafe パッケージ

組み込みパッケージ unsafe はコンパイラに認識され、インポートパス "unsafe" を通じてアクセス可能です。このパッケージは型システムに違反する操作を含む低レベルプログラミング機能を提供します。unsafe パッケージを使用するパッケージは、型安全性を手動で検証する必要があり、移植性が保証されない場合があります。パッケージは以下のインターフェイスを提供します:

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
func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte

Pointerポインタ型ですが、Pointer 値は参照解除できません。基底型uintptr であるポインタまたは値は、基底型が Pointer である型に変換でき、その逆も可能です。それぞれの型が型パラメータである場合、それぞれの型セット内のすべての型は同じ基底型を持つ必要があり、それぞれ uintptrPointer でなければなりません。Pointeruintptr 間の変換の効果は実装定義です。

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

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

func f[P ~*B, B any](p P) uintptr {
	return uintptr(unsafe.Pointer(p))
}

var p ptr = nil

関数 AlignofSizeof は任意の型の式 x を取り、あたかも var v = x を通じて変数 v が宣言されたかのように、仮想的な変数 v のアラインメントまたはサイズをそれぞれ返します。

関数 Offsetof は(場合によっては括弧で囲まれた)セレクタ s.f を取ります。これは s または *s で示される構造体のフィールド f を示し、構造体のアドレスを基準としたフィールドのオフセットをバイト単位で返します。f埋め込まれたフィールドの場合、構造体のフィールドを通じてポインタによる間接参照なしで到達可能でなければなりません。フィールド f を持つ構造体 s の場合:

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

コンピュータアーキテクチャでは、メモリアドレスがアラインメントされていることが要求される場合があります。つまり、変数のアドレスが変数の型のアラインメントという要素の倍数であることが求められます。関数 Alignof は任意の型の変数を示す式を取り、バイト単位で変数(の型)のアラインメントを返します。変数 x の場合:

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

T の(変数)は、T型パラメータである場合、または可変サイズの要素やフィールドを含む配列または構造体型である場合に可変サイズを持ちます。それ以外の場合、サイズは定数です。AlignofOffsetofSizeof の呼び出しは、引数(または Offsetof のセレクタ式 s.f における構造体 s)が定数サイズの型である場合、型 uintptr定数式です。

関数 Addptrlen を加算し、更新されたポインタ unsafe.Pointer(uintptr(ptr) + uintptr(len)) を返しますGo 1.17len 引数は整数型または型なしの定数である必要があります。定数 len 引数は型 int の値で表現可能でなければなりません;型なしの定数の場合は型 int が与えられます。Pointer有効な使用に関するルールは引き続き適用されます。

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

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

ただし、特殊なケースとして、ptrnillen がゼロの場合、Slicenil を返します Go 1.17

len 引数は整数型または型なしの定数である必要があります。定数 len 引数は非負数で、型 int の値で表現可能でなければなりません;型なしの定数の場合は型 int が与えられます。実行時に、len が負の場合、または ptrnillen がゼロでない場合、実行時パニックが発生します Go 1.17

関数 SliceDataslice 引数の基礎となる配列へのポインタを返します。スライスの容量 cap(slice) がゼロでない場合、そのポインタは &slice[:1][0] です。slicenil の場合、結果は nil です。それ以外の場合は、未指定のメモリアドレスへの非 nil ポインタです Go 1.20

関数 String は、基礎となるバイトが ptr から始まり、長さが len である string 値を返します。ptrlen の引数には、関数 Slice と同じ要件が適用されます。len がゼロの場合、結果は空の文字列 "" です。Go の文字列は不変であるため、String に渡されるバイトはその後変更してはいけません Go 1.20

関数 StringDatastr 引数の基礎となるバイトへのポインタを返します。空の文字列の場合、戻り値は未指定であり、nil かもしれません。Go の文字列は不変であるため、StringData によって返されるバイトは変更してはいけません Go 1.20

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

数値型については、以下のサイズが保証されています:

型                                 サイズ(バイト)

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. 構造体型の変数 x について:unsafe.Alignof(x) は、x の各フィールド f に対する unsafe.Alignof(x.f) の値のうち最大のものですが、少なくとも 1 です。

  3. 配列型の変数 x について:unsafe.Alignof(x) は配列の要素型の変数のアラインメントと同じです。

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