Error Handling
Examples in
V
struct User {
id int
name string
}
struct Repo {
users []User
}
fn new_repo() Repo {
return Repo {
users: [User{1, 'Andrew'}, User {2, 'Bob'}, User {10, 'Charles'}]
}
}
fn (r Repo) find_user_by_id(id int) ?User {
for user in r.users {
if user.id == id {
// V automatically wraps this into an option type
return user
}
}
return error('User $id not found')
}
fn main() {
repo := new_repo()
user := repo.find_user_by_id(10) or { // Option types must be handled by `or` blocks
return // `or` block must end with `return`, `break`, or `continue`
}
println(user.id) // "10"
println(user.name) // "Charles"
}
// V combines Option and Result into one type, so you don't need to decide which one to use.
// The amount of work required to "upgrade" a function to an optional function is minimal: you have to add a ? to the return type and return an error when something goes wrong.
// If you don't need to return an error, you can simply return none.
// This is the primary way of handling errors in V. They are still values, like in Go, but the advantage is that errors can't be unhandled, and handling them is a lot less verbose.
// err is defined inside an or block and is set to the string message passed to the error() function. err is empty if none was returned.
user := repo.find_user_by_id(7) or {
println(err) // "User 7 not found"
return
}
// You can also propagate errors:
resp := http.get(url)?
println(resp.body)
// http.get returns ?http.Response. It was called with ?, so the error is propagated to the calling function (which must return an optional) or in case of main leads to a panic.
// Basically the code above is a shorter version of
resp := http.get(url) or {
panic(err)
}
println(resp.body)
// V does not have a way to force unwrap an optional (like Rust's unwrap() or Swift's !). You have to use or { panic(err) } instead.