いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-634 (unsafe.Slice, unsafe.SliceData関数を用いて*byteと[]byteを相互変換)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

unsafeパッケージって、Goの安全性の枠から外れる操作をするパッケージなので、基本的に使わないほうが良いものですが、知ってると便利なパッケージでもあります。

cgoを使う場合はほぼ必須です。特に unsafe.Pointer はめっちゃ使います。

unsafe.Pointer は、C言語でいう (void *) と同じものとなるので、これを利用することで任意の型にキャストできます。

unsafe.Pointer については、以前の記事でサンプル作ったので、そちらご参照ください。

今回は、*byte[]byteの相互変換について。主に低レベルなAPI操作やcgoなどで利用したりします。

unsafe.SliceData は、特定のスライス []T*T に変換してくれます。これはGoのヒープメモリを指すポインタとなります。

unsafe.Slice は、逆を行うものです。つまり、*T[]T にしてくれる関数。ポインタとサイズを渡すとスライスにして返してくれます。 こちらは元のデータが指すポインタをそのまま指した状態で返してくれます。つまり、C側のポインタを渡してスライスにした場合はC側のスタックメモリをそのまま指している状態となります。

元のデータのポインタを直接指しているので、C側から受け取った char * なんかを unsafe.Slice を使ってスライスにして、それを変更などするとC側のスタックメモリを直接変更することになります。非常に危険です。データを見る分には問題ありません。

今回は、使い方だけサンプルとして。実際にcgoを使ってやり取りするサンプルは次回。

サンプル

package unsafes

import (
    "bytes"
    "fmt"
    "unsafe"
)

// Slice は、unsafe.SliceData() と unsafe.Slice() のサンプルです。
//
// unsafe.SliceData() は、特定のスライスを *T に変換する関数。
// 逆を行ってくれるのが unsafe.Slice() となる。
//
// REFERENCES:
//   - https://pkg.go.dev/unsafe@go1.25.3#SliceData
func Slice() error {
    var (
        original = []byte("helloworld")
        result   []byte
        ptr      *byte
    )
    ptr = unsafe.SliceData(original)          // []byteを*byteに変換
    result = unsafe.Slice(ptr, len(original)) // *byteを[]byteに変換

    fmt.Printf("b1 equals b2: %v\n", bytes.Equal(original, result))

    return nil
}

実行

$ task
task: [build] go build -o "/home/dev/dev/try-golang/try-golang" .
task: [run] ./try-golang -onetime

ENTER EXAMPLE NAME: unsafe_slice

[Name] "unsafe_slice"
b1 equals b2: true


[Elapsed] 15.886µs

参考情報

個人的Goのおすすめ書籍

個人的に読んでとても勉強になった書籍さんたちです。


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。