doc: enhance the Option example, tweak the Calling C section (#5830)
parent
cf7d03bda6
commit
f5579525c4
85
doc/docs.md
85
doc/docs.md
|
@ -70,6 +70,7 @@ you can do in V.
|
|||
|
||||
* [Advanced](#advanced)
|
||||
* [Calling C functions from V](#calling-c-functions-from-v)
|
||||
* [Debugging generated C code](#debugging-generated-c-code)
|
||||
* [Conditional compilation](#conditional-compilation)
|
||||
* [Compile time pseudo variables](#compile-time-pseudo-variables)
|
||||
* [Reflection via codegen](#reflection-via-codegen)
|
||||
|
@ -174,6 +175,7 @@ fn foo() (int, int) {
|
|||
a, b := foo()
|
||||
println(a) // 2
|
||||
println(b) // 3
|
||||
c, _ := foo() // ignore values using `_`
|
||||
```
|
||||
|
||||
Functions can return multiple values.
|
||||
|
@ -1329,7 +1331,7 @@ sum := World(Moon{})
|
|||
```
|
||||
|
||||
To check whether a sum type instance holds a certain type, use `sum is Type`.
|
||||
To cast a sum type to one of its variants you use `sum as Type`:
|
||||
To cast a sum type to one of its variants you can use `sum as Type`:
|
||||
|
||||
```v
|
||||
fn (m Mars) dust_storm() bool
|
||||
|
@ -1347,6 +1349,8 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
### Matching sum types
|
||||
|
||||
You can also use `match` to determine the variant:
|
||||
|
||||
```v
|
||||
|
@ -1401,6 +1405,7 @@ Note: shadowing only works when the match expression is a variable. It will not
|
|||
|
||||
### Option/Result types and error handling
|
||||
|
||||
Option types are declared with `?Type`:
|
||||
```v
|
||||
struct User {
|
||||
id int
|
||||
|
@ -1411,12 +1416,6 @@ 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 {
|
||||
|
@ -1428,7 +1427,9 @@ fn (r Repo) find_user_by_id(id int) ?User {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
repo := new_repo()
|
||||
repo := Repo {
|
||||
users: [User{1, 'Andrew'}, User {2, 'Bob'}, User {10, 'Charles'}]
|
||||
}
|
||||
user := repo.find_user_by_id(10) or { // Option types must be handled by `or` blocks
|
||||
return
|
||||
}
|
||||
|
@ -1458,29 +1459,38 @@ user := repo.find_user_by_id(7) or {
|
|||
}
|
||||
```
|
||||
|
||||
There are three ways of handling an optional.
|
||||
### Handling optionals
|
||||
|
||||
The first method is to propagate the error:
|
||||
There are three ways of handling an optional. The first method is to
|
||||
propagate the error:
|
||||
|
||||
```v
|
||||
resp := http.get(url)?
|
||||
println(resp.text)
|
||||
```
|
||||
import net.http
|
||||
|
||||
`http.get` returns `?http.Response`. Because it was called with `?`, the error will be propagated to the calling function
|
||||
(which must return an optional as well). If it is used in the `main()` function it will `panic` instead, since the error
|
||||
cannot be propagated any further.
|
||||
|
||||
The code above is essentially a condensed version of
|
||||
|
||||
```v
|
||||
resp := http.get(url) or {
|
||||
return error(err)
|
||||
fn f(url string) ?string {
|
||||
resp := http.get(url)?
|
||||
return resp.text
|
||||
}
|
||||
println(resp.text)
|
||||
```
|
||||
|
||||
The second is to break from execution early:
|
||||
`http.get` returns `?http.Response`. Because `?` follows the call, the
|
||||
error will be propagated to the caller of `f`. When using `?` after a
|
||||
function call producing an optional, the enclosing function must return
|
||||
an optional as well. If error propagation is used in the `main()`
|
||||
function it will `panic` instead, since the error cannot be propagated
|
||||
any further.
|
||||
|
||||
The body of `f` is essentially a condensed version of:
|
||||
|
||||
```v
|
||||
resp := http.get(url) or {
|
||||
return error(err)
|
||||
}
|
||||
return resp.text
|
||||
```
|
||||
|
||||
---
|
||||
The second method is to break from execution early:
|
||||
|
||||
```v
|
||||
user := repo.find_user_by_id(7) or {
|
||||
|
@ -1492,8 +1502,9 @@ Here, you can either call `panic()` or `exit()`, which will stop the execution o
|
|||
or use a control flow statement (`return`, `break`, `continue`, etc) to break from the current block.
|
||||
Note that `break` and `continue` can only be used inside a `for` loop.
|
||||
|
||||
---
|
||||
The third method is to provide a default value at the end of the `or` block. In case of an error,
|
||||
that value would be assigned instead, so it must have the same type as the `Option` being handled.
|
||||
that value would be assigned instead, so it must have the same type as the content of the `Option` being handled.
|
||||
|
||||
```v
|
||||
fn do_something(s string) ?string {
|
||||
|
@ -1506,7 +1517,7 @@ b := do_something('bar') or { 'default' } // b will be 'default'
|
|||
```
|
||||
|
||||
V does not have a way to forcibly "unwrap" an optional (as other languages do, for instance Rust's `unwrap()`
|
||||
or Swift's `!`). To do this use `or { panic(err) }` instead.
|
||||
or Swift's `!`). To do this, use `or { panic(err) }` instead.
|
||||
|
||||
## Generics
|
||||
|
||||
|
@ -1844,6 +1855,8 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
### #flag
|
||||
|
||||
Add `#flag` directives to the top of your V files to provide C compilation flags like:
|
||||
|
||||
- `-I` for adding C include files search paths
|
||||
|
@ -1863,6 +1876,8 @@ NB: Each flag must go on its own line (for now)
|
|||
#flag linux -DIMGUI_IMPL_API=
|
||||
```
|
||||
|
||||
### Including C code
|
||||
|
||||
You can also include C code directly in your V module. For example, let's say that your C code is located in a folder named 'c' inside your module folder. Then:
|
||||
|
||||
* Put a v.mod file inside the toplevel folder of your module (if you
|
||||
|
@ -1885,26 +1900,28 @@ Module {
|
|||
#include "header.h"
|
||||
```
|
||||
NB: @VROOT will be replaced by V with the *nearest parent folder, where there is a v.mod file*.
|
||||
Any .v file beside or below the folder where the v.mod file is, can use #flag @VROOT/abc to refer to this folder.
|
||||
Any .v file beside or below the folder where the v.mod file is, can use `#flag @VROOT/abc` to refer to this folder.
|
||||
The @VROOT folder is also *prepended* to the module lookup path, so you can *import* other
|
||||
modules under your @VROOT, by just naming them.
|
||||
|
||||
The instructions above will make V look for an compiled .o file in your module folder/c/implementation.o .
|
||||
The instructions above will make V look for an compiled .o file in your module `folder/c/implementation.o`.
|
||||
If V finds it, the .o file will get linked to the main executable, that used the module.
|
||||
If it does not find it, V assumes that there is a `@VROOT/c/implementation.c` file,
|
||||
and tries to compile it to a .o file, then will use that.
|
||||
|
||||
This allows you to have C code, that is contained in a V module, so that its distribution is easier.
|
||||
You can see a complete example for using C code in a V wrapper module here:
|
||||
[minimal V project, that has a module, which contains C code](https://github.com/vlang/v/tree/master/vlib/v/tests/project_with_c_code)
|
||||
You can see a complete minimal example for using C code in a V wrapper module here:
|
||||
[project_with_c_code](https://github.com/vlang/v/tree/master/vlib/v/tests/project_with_c_code).
|
||||
|
||||
You can use `-cflags` to pass custom flags to the backend C compiler. You can also use `-cc` to change the default C backend compiler.
|
||||
For example: `-cc gcc-9 -cflags -fsanitize=thread`.
|
||||
|
||||
### C types
|
||||
|
||||
Ordinary zero terminated C strings can be converted to V strings with `string(cstring)` or `string(cstring, len)`.
|
||||
|
||||
NB: `string/1` and `string/2` do NOT create a copy of the `cstring`, so you should NOT free it after calling `string()`. If you need to make a copy of the C string (some libc APIs like `getenv/1` pretty much require that, since they
|
||||
return pointers to internal libc memory), you can use: `cstring_to_vstring(cstring)`
|
||||
NB: Each `string(...)` function does NOT create a copy of the `cstring`, so you should NOT free it after calling `string()`. If you need to make a copy of the C string (some libc APIs like `getenv` pretty much require that, since they
|
||||
return pointers to internal libc memory), you can use `cstring_to_vstring(cstring)`.
|
||||
|
||||
On Windows, C APIs often return so called `wide` strings (utf16 encoding).
|
||||
These can be converted to V strings with `string_from_wide(&u16(cwidestring))` .
|
||||
|
@ -1920,7 +1937,9 @@ To cast a `voidptr` to a V reference, use `user := &User(user_void_ptr)`.
|
|||
|
||||
`voidptr` can also be dereferenced into a V struct through casting: `user := User(user_void_ptr)`.
|
||||
|
||||
[Socket.v has an example which calls C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) .
|
||||
[socket.v has an example which calls C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) .
|
||||
|
||||
## Debugging generated C code
|
||||
|
||||
To debug issues in the generated C code, you can pass these flags:
|
||||
|
||||
|
|
Loading…
Reference in New Issue