Skip to main content

v-lang

The V language rules that make code which looks right fail to compile or behave wrongly - ?T versus !T, sum types and match exhaustiveness, mut receivers, module names matching directories, comptime $ forms, and explicit type conversion. Use when writing or reviewing any V code that uses an Option, a Result, a sum type, a match, generics, or a custom flag, and when a V compiler error names an option, a result, exhaustiveness, mutability, or a module. Does not cover the build and test loop (see v-workflow), writing tests (see v-testing), reading a V project through the MCP server (see v-mcp), scripting in V (see v-scripts), or the wider command surface (see v-tools).

Quellinformationen

Repository
vlang/v
Letzte Quellaktivität
4. Oktober 2026 um 06:11
Erkannte Sprache von SKILL.md
Englisch
Sterne
38.011
Forks
2.302

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
5 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
v-lang
description
The V language rules that make code which looks right fail to compile or behave wrongly - ?T versus !T, sum types and match exhaustiveness, mut receivers, module names matching directories, comptime $ forms, and explicit type conversion. Use when writing or reviewing any V code that uses an Option, a Result, a sum type, a match, generics, or a custom flag, and when a V compiler error names an option, a result, exhaustiveness, mutability, or a module. Does not cover the build and test loop (see v-workflow), writing tests (see v-testing), reading a V project through the MCP server (see v-mcp), scripting in V (see v-scripts), or the wider command surface (see v-tools).
license
MIT
# The V rules that bite Most mistakes an agent makes in V are not algorithmic. They are these rules, and each one fails in a way that does not look like the mistake. ## Resource Routing - `references/OPTION-RESULT.md` - Read when deciding whether a function returns `?T` or `!T`, or when an `or {}` block is not doing what you expected. - `references/SUMTYPES.md` - Read when modelling a closed set of states, or when `match` reports a non-exhaustive match. - `references/COMPTIME.md` - Read when a symbol only exists on some platforms, or when reaching for reflection or `$embed_file`. - `references/MUTABILITY.md` - Read when an assignment is rejected, or when a mutation to a field does not reach the caller. ## Quick Reference | You want | Write | Not | | --- | --- | --- | | A value that may be absent | `fn f() ?int` | `return 0` as a sentinel | | An operation that can fail | `fn f() !int` | `return -1` | | Unwrap, no default | `x or { return error('...') }` | `x or { 0 }` on a result | | Unwrap, with a default | `x or { 0 }` on an option | `x or { return }` on an option | | Branch on a closed set | `enum` + exhaustive `match` | a string constant | | Mutate an argument | `fn f(mut x T)` | `x = ...` silently failing | | Mutate the caller's struct | `fn (mut t &T)` | `fn (mut t T)` (a copy) | | Run code at compile time | `$if`, `$for` | a runtime `if` | ## `?T` is not `!T` `?T` holds a value or `none`. `!T` holds a value or an error. They unwrap differently, and using one where the other belongs is a type error rather than a logic error. ```v ignore // An option: absence is part of the answer. fn find_port(cfg Config) ?int { if !cfg.has_port { return none } return cfg.port } // A result: the operation can fail, and the failure carries why. fn read_port(path string) !int { lines := os.read_lines(path) or { return error('cannot read ${path}: ${err.msg()}') } ... } ``` The rule that catches people: inside `or { ... }` on a **result**, the block must produce that result's error value, so it is `return error(...)` and not a bare `return`. On an **option**, `or { default }` supplies a value. **Default**: return `!T` for anything that touches the outside world, and `?T` for a lookup that is legitimately absent. Full detail, including how to propagate and when a default is honest, in `references/OPTION-RESULT.md`. ## Sum types and match V enums plus `match` are the way to model a closed set. `match` over an enum is checked for exhaustiveness, which is the point: adding a variant turns every incomplete `match` into a compile error instead of a silent fallthrough. The diagnostic is exact: `non-exhaustive match expression without `else``. Two ways out — handle every variant, or add an `else` branch and accept that a new variant changes nothing. ```v ignore enum Status { pending running done failed } fn label(s Status) string { return match s { .pending { 'queued' } .running { 'in progress' } .done { 'finished' } .failed { 'could not finish' } } } ``` Variants are shared: `type Job = Status | string` is a sum type, and a `match` over it must handle both sides. See `references/SUMTYPES.md`. ## mut is not optional Function arguments are immutable. A receiver is immutable unless it is declared `mut`. This is the single most common V compile error, and it always has the same cause: the author assumed mutation was the default. ```v ignore // Rejected: `app` is immutable. // fn serve(app App) { app.port = 8080 } // Accepted: the argument is mutable. fn serve(mut app App) { app.port = 8080 } // Accepted, and it reaches the caller: the receiver is a pointer. fn serve(app &App) { app.port = 8080 } // Accepted: the field itself is declared mutable. struct Server { mut: port int } ``` `mut` on a **value** receiver mutates a copy, so the caller's struct is unchanged. `mut` on a **pointer** receiver mutates the caller's. That difference is silent at the call site, which is why `references/MUTABILITY.md` exists. ## Module names must match directories `module foo` must live in a directory named `foo`. A mismatch imports cleanly and then resolves to nothing, with no error pointing at the name. The `module` line carries no hierarchy — the directory nesting supplies it. This is why a project built by `v new` has `src/main.v` with `module main` rather than `module src`. ## Comptime is `$`, and it excludes branches Anything starting with `$` runs while the compiler runs. The branches of an `$if` are **excluded entirely** on a platform that does not match, which is the only reason a platform-specific import inside one is safe. ```v ignore $if windows { import sys.windows as wsys } $if linux { import sys.linux } ``` A runtime `if` that mentions a platform-specific symbol will not compile on the other platforms, because there is no exclusion. Available in `$if`: `windows`, `linux`, `macos`, `js`, `freebsd`, `android`, `debug`, `prod`, and your own `$d custom_flag ? { ... }` — note the `?`. ## No implicit conversions `int` is 32 bit and `i64` is 64. `f64` and `int` do not mix. Nothing converts implicitly, which is deliberate: a silent narrowing is a bug you find later. Be explicit at the boundary, and prefer `strconv` over hand-rolled parsing. ## Validation After changing V code, prove it rather than reading it again: ```bash v -check path/to/file.v # type-check only, no binary v fmt -verify path/to/file.v # would the formatter change it? ``` For library code rather than a `main` module, `-check` alone fails with *"project must include a `main` module"*; use `v -check -shared path/to/file.v`. Run both before you report the change done. See `v-workflow` for the full loop. ## Related Skills - **The build and test loop**: see [v-workflow](../v-workflow/SKILL.md) for `v.mod`, dependencies, when `./v self` is required, and the flags that go before the subcommand. - **Writing tests**: see [v-testing](../v-testing/SKILL.md) when the change needs a `_test.v` file, or when `?T` and `!T` need asserting. - **Asking the compiler**: see [v-mcp](../v-mcp/SKILL.md) when you want the declarations, references or diagnostics of a file without reading it, or when you want to edit through an AST-aware rename. - **Memory and GC**: see [v-memory](../v-memory/SKILL.md) for GC modes, ownership checking and `unsafe`.
Auf GitHub ansehen