unsafe.String and unsafe.StringData

Package unsafe … The function String returns a string value whose underlying bytes start at ptr and whose length is len. The same requirements apply to the ptr and len argument as in the function Slice. If len is zero, the result is the empty string "". Since Go strings are immutable, the bytes passed to String must not be modified afterwards. [Go 1.20] The function StringData returns a pointer to the underlying bytes of the str argument.


unsafe.Slice

Package unsafe … The function Slice returns a slice whose underlying array starts at ptr and whose length and capacity are len. Slice(ptr, len) is equivalent to (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:] except that, as a special case, if ptr is nil and len is zero, Slice returns nil [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be non-negative and representable by a value of type int; if it is an untyped constant it is given type int.


Pointer Arithmetic

I mentioned a few days ago that pointer arithmetic is possible through the unsafe package. Here’s how to do it. Package unsafe … The function Add adds len to ptr and returns the updated pointer unsafe.Pointer(uintptr(ptr) + uintptr(len)) [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be representable by a value of type int; if it is an untyped constant it is given type int.


Variable vs Constant size

You’ll likely remember that certain built-in functions can sometimes evaluate to constants, rather than variables. For example: var x [10]int var y []int len(x) // evaluates to a constant at compile time len(y) // evaluates to a variable at runtime Package unsafe … A (variable of) type T has variable size if T is a type parameter, or if it is an array or struct type containing elements or fields of variable size.


Variable Alignment

Package unsafe … Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable’s type’s alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes. For a variable x: uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0 I don’t think I’m qualified to really talk much more about this.


Offsetof

Package unsafe … The function Offsetof takes a (possibly parenthesized) selector s.f, denoting a field f of the struct denoted by s or *s, and returns the field offset in bytes relative to the struct’s address. If f is an embedded field, it must be reachable without pointer indirections through fields of the struct. For a struct s with field f: uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f)) I expect this is neither too confusing, nor too useful for most of us.


Determining the size of a variable

Package unsafe … The functions Alignof and Sizeof take an expression x of any type and return the alignment or size, respectively, of a hypothetical variable v as if v was declared via var v = x. Grammar nit! That should be “…as if v were…” But nobody cares about that. While Alignof is unlikely to be used outside of CGO, or low-level optimizations, Sizeof can be useful for us mere mortals.

Subscribe to Boldly Go: Daily

Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.

Unsure? Browse the archive.


Package unsafe

Today we’re venturing into dangerous territory… the unsafe package! You can go years working in Go (as I have) without ever using unsafe, or just barely bumping into it. On the other hand, somd developers spend significant time using unsafe, to get the utmost performance out of their code, by working around the type system. Using unsafe can be powerful and beneficial. But… do it with the understanding that you’re giving up the benefits of memory and type safety, and cross-platform compatibility.


Run-time panics

Run-time panics Execution errors such as attempting to index an array out of bounds trigger a run-time panic equivalent to a call of the built-in function panic with a value of the implementation-defined interface type runtime.Error. That type satisfies the predeclared interface type error. The exact error values that represent distinct run-time error conditions are unspecified. package runtime type Error interface { error // and perhaps other methods } We’ve already covered the built-in panic function, and the related recover.


Errors

Today we’re looking at errors, and the built-in error interface. For a concept that’s so central to the Go ethos, the spec has surprisingly little to say about it: Errors The predeclared type error is defined as type error interface { Error() string } It is the conventional interface for representing an error condition, with the nil value representing no error. For instance, a function to read data from a file might be defined:


Program execution

Program execution A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. The main package must have package name main and declare a function main that takes no arguments and returns no value. func main() { … } Program execution begins by initializing the program and then invoking the function main in package main. When that function invocation returns, the program exits.