More in Go & Rust — page 9
cbindgen: Auto-generate C/C++ Headers for Rust
cbindgen automatically generates C/C++ headers for your Rust code, saving you from writing tedious FFI boilerplate. Use it when exposing a Rust library to other languages. Its feature set is ad-hoc, so it may not support your specific edge case out of the box.
Rust's `bindgen`: Auto-Generate FFI to C/C++
`bindgen` is a translator that reads C/C++ headers and writes the unsafe Rust FFI code to call them. It's used to integrate Rust with existing C libraries, like system APIs or legacy code, saving you from writing bindings by hand.
Rust: Expose Functions to C with `#[no_mangle]`
The `#[no_mangle]` attribute tells the Rust compiler not to alter a function's name, exposing a stable symbol for C code to call. Use it with `extern "C"` to create Rust libraries for other languages. The footgun is forgetting `extern "C"`, causing crashes.
Rust: Bridging C Strings with CStr and CString
CString and CStr are Rust's safe wrappers for C's nul-terminated strings. CString builds a C-compatible string to pass *out* of Rust; CStr interprets one coming *in*. Use them for any FFI calls.
Rust's `libc` Crate: Speaking the OS's Language
The `libc` crate is Rust's dictionary for C types, letting you talk to the OS. Use it for system calls or linking C libraries, like when building low-level network tools.
Rust's `extern` Block: Talking to Other Languages
An `extern` block is Rust's contract for calling code from other languages, like C. You declare external functions and statics, promising they exist. Use it for FFI to call system libraries, but know all calls are `unsafe` as Rust can't verify them.
Go Assembly: A Semi-Abstract Instruction Set
Go's assembler isn't a direct mapping to machine code; it's a semi-abstract instruction set. A `MOV` might become a `clear` or `load`. This is what you see with `go tool compile -S`. The footgun is assuming your assembly maps 1:1 to the final machine code.
Rust's Pin: Fixing a Value's Memory Address
Pin<P> tells the Rust compiler a value must not move from its memory location. Think of it as nailing an object to a specific spot on the memory shelf. This is crucial for self-referential types, like those in async runtimes.
Rust Const Generics: Parameterize by Value, Not Just Type
Const generics let Rust types be parameterized by values, not just other types. This allows writing code generic over array sizes, like `Matrix<T, const N: usize>`, ensuring dimensions are checked at compile time.
Rust Procedural Macros: Code That Writes Code
Procedural macros are compile-time functions that write Rust code for you. They power common patterns like Serde's `#[derive(Serialize)]`. The main footgun is hygiene: generated code can clash with local variables, so authors must use absolute paths to be…
Cgo: The Bridge Between Go and C Code
Cgo is Go's bridge to the C world, letting you call C functions and use C types from your Go code. It's for leveraging existing C libraries or low-level OS APIs. The footgun: cgo calls have high overhead and break Go's simple cross-compilation.
Go's `unsafe` Package: Breaking the Rules for Performance
Go's `unsafe` package lets you bypass type safety, treating memory like C with raw pointers for performance gains. It's used for low-level optimizations and C interoperability. The footgun: its behavior isn't guaranteed across Go versions, making code fragile.
Rust Raw Pointers: When References Aren't Enough
Raw pointers (*const T, *mut T) are Rust's C-style pointers, bypassing the borrow checker. They're used for FFI or building low-level abstractions. The footgun is assuming they're safe; they can be null or dangling, requiring `unsafe` to dereference.
Rust's `unsafe` Keyword: Five Superpowers, Zero Guarantees
Rust's `unsafe` keyword lets you bypass certain compile-time memory safety guarantees for low-level tasks like OS interaction or FFI. The footgun is thinking it disables all safety; it only enables five specific 'superpowers,' making you responsible for…
Rust Declarative Macros (`macro_rules!`)
Think of `macro_rules!` as 'find and replace' for your code's structure. It matches patterns at compile time and expands them into boilerplate you don't want to write. It's used for helpers like `vec![]`.
Go Reflection: Inspecting Types at Runtime
Go's `reflect` package lets your program inspect and manipulate variables of unknown types at runtime. This is the engine behind JSON marshaling and generic frameworks. Misuse leads to slow code and runtime panics; always prefer interfaces when possible.
Go Linker Flags: Injecting Data at Build Time
Go's `-ldflags` lets you inject data into your program at build time. This is perfect for embedding version numbers or git commit hashes into variables without hardcoding them. The main footgun is that the target variable must be a top-level string.
Rust `cfg`: Compile Code for Specific Targets
Rust's `cfg` attribute acts like a compile-time switch, including or excluding code based on the target platform or features. It's used for cross-platform support (e.g., Windows vs. Unix) or enabling optional dependencies.
Go Execution Tracer: Pinpointing Concurrency Bottlenecks
Go's Execution Tracer creates a visual timeline of your program, capturing goroutine state changes, syscalls, and GC events. It's essential for diagnosing subtle concurrency issues like lock contention. The main footgun is misusing annotations for work.
Fuzz Testing in Rust with cargo-fuzz
Fuzz testing automatically finds bugs by feeding your code pseudo-random inputs. Use `cargo-fuzz` to stress-test parsers and APIs that handle untrusted data. The main footgun is assuming random bytes are enough; effective fuzzing needs structure-aware inputs.