docs: format more code blocks (#8011)

pull/8016/head
Lukas Neubert 2021-01-10 20:21:37 +01:00 committed by GitHub
parent a8378273a5
commit 6720dbef52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 152 additions and 132 deletions

View File

@ -213,9 +213,9 @@ or thinking about the order of files and declarations.
### Returning multiple values ### Returning multiple values
```v nofmt ```v
fn foo() (int, int) { fn foo() (int, int) {
return 2, 3 return 2, 3
} }
a, b := foo() a, b := foo()
@ -226,21 +226,21 @@ c, _ := foo() // ignore values using `_`
### Variable number of arguments ### Variable number of arguments
```v nofmt ```v
fn sum(a ...int) int { fn sum(a ...int) int {
mut total := 0 mut total := 0
for x in a { for x in a {
total += x total += x
} }
return total return total
} }
println(sum()) // Output: 0
println(sum(1)) // 1
println(sum(2,3)) // 5
println(sum()) // 0
println(sum(1)) // 1
println(sum(2, 3)) // 5
// using array decomposition // using array decomposition
a := [2,3,4] a := [2, 3, 4]
println(sum(...a)) // <-- using prefix ... here. output: 9 println(sum(...a)) // <-- using prefix ... here. output: 9
b := [5, 6, 7] b := [5, 6, 7]
println(sum(...b)) // output: 18 println(sum(...b)) // output: 18
``` ```
@ -402,12 +402,11 @@ negative values).
### Strings ### Strings
```v nofmt ```v
name := 'Bob' name := 'Bob'
println(name.len) println(name.len)
println(name[0]) // indexing gives a byte B println(name[0]) // indexing gives a byte B
println(name[1..3]) // slicing gives a string 'ob' println(name[1..3]) // slicing gives a string 'ob'
windows_newline := '\r\n' // escape special characters like in C windows_newline := '\r\n' // escape special characters like in C
assert windows_newline.len == 2 assert windows_newline.len == 2
``` ```
@ -436,7 +435,7 @@ Both single and double quotes can be used to denote strings. For consistency,
For raw strings, prepend `r`. Raw strings are not escaped: For raw strings, prepend `r`. Raw strings are not escaped:
```v nofmt ```v
s := r'hello\nworld' s := r'hello\nworld'
println(s) // "hello\nworld" println(s) // "hello\nworld"
``` ```
@ -445,7 +444,7 @@ println(s) // "hello\nworld"
Basic interpolation syntax is pretty simple - use `$` before a variable name. Basic interpolation syntax is pretty simple - use `$` before a variable name.
The variable will be converted to a string and embedded into the literal: The variable will be converted to a string and embedded into the literal:
```v nofmt ```v
name := 'Bob' name := 'Bob'
println('Hello, $name!') // Hello, Bob! println('Hello, $name!') // Hello, Bob!
``` ```
@ -456,24 +455,24 @@ Format specifiers similar to those in C's `printf()` are also supported.
`f`, `g`, `x`, etc. are optional and specify the output format. `f`, `g`, `x`, etc. are optional and specify the output format.
The compiler takes care of the storage size, so there is no `hd` or `llu`. The compiler takes care of the storage size, so there is no `hd` or `llu`.
```v nofmt ```v
x := 123.4567 x := 123.4567
println('x = ${x:4.2f}') println('x = ${x:4.2f}')
println('[${x:10}]') // pad with spaces on the left println('[${x:10}]') // pad with spaces on the left
println('[${int(x):-10}]') // pad with spaces on the right println('[${int(x):-10}]') // pad with spaces on the right
``` ```
### String operators ### String operators
```v nofmt ```v
name := 'Bob' name := 'Bob'
bobby := name + 'by' // + is used to concatenate strings bobby := name + 'by' // + is used to concatenate strings
println(bobby) // "Bobby" println(bobby) // "Bobby"
mut s := 'hello ' mut s := 'hello '
s += 'world' // `+=` is used to append to a string s += 'world' // `+=` is used to append to a string
println(s) // "hello world" println(s) // "hello world"
``` ```
All operators in V must have values of the same type on both sides. All operators in V must have values of the same type on both sides.
You cannot concatenate an integer to a string: You cannot concatenate an integer to a string:
@ -519,10 +518,10 @@ All of these will be assigned the same value, 123. They will all have type
V also supports writing numbers with `_` as separator: V also supports writing numbers with `_` as separator:
```v nofmt ```v
num := 1_000_000 // same as 1000000 num := 1_000_000 // same as 1000000
three := 0b0_11 // same as 0b11 three := 0b0_11 // same as 0b11
float_num := 3_122.55 // same as 3122.55 float_num := 3_122.55 // same as 3122.55
hexa := 0xF_F // same as 255 hexa := 0xF_F // same as 255
oct := 0o17_3 // same as 0o173 oct := 0o17_3 // same as 0o173
``` ```
@ -547,19 +546,16 @@ will have the type of `f64`.
### Arrays ### Arrays
```v nofmt ```v
mut nums := [1, 2, 3] mut nums := [1, 2, 3]
println(nums) // "[1, 2, 3]" println(nums) // "[1, 2, 3]"
println(nums[1]) // "2" println(nums[1]) // "2"
nums[1] = 5 nums[1] = 5
println(nums) // "[1, 5, 3]" println(nums) // "[1, 5, 3]"
println(nums[0..2]) // slicing gives an array "[1, 5]" println(nums[0..2]) // slicing gives an array "[1, 5]"
println(nums.len) // "3" println(nums.len) // "3"
nums = [] // The array is now empty nums = [] // The array is now empty
println(nums.len) // "0" println(nums.len) // "0"
// Declare an empty array: // Declare an empty array:
users := []int{} users := []int{}
``` ```
@ -578,15 +574,13 @@ See [Access modifiers](#access-modifiers).
#### Array operations #### Array operations
```v nofmt ```v
mut nums := [1, 2, 3] mut nums := [1, 2, 3]
nums << 4 nums << 4
println(nums) // "[1, 2, 3, 4]" println(nums) // "[1, 2, 3, 4]"
// append array // append array
nums << [5, 6, 7] nums << [5, 6, 7]
println(nums) // "[1, 2, 3, 4, 5, 6, 7]" println(nums) // "[1, 2, 3, 4, 5, 6, 7]"
mut names := ['John'] mut names := ['John']
names << 'Peter' names << 'Peter'
names << 'Sam' names << 'Sam'
@ -613,12 +607,12 @@ arr := []int{len: 5, init: -1}
Setting the capacity improves performance of insertions, Setting the capacity improves performance of insertions,
as it reduces the number of reallocations needed: as it reduces the number of reallocations needed:
```v nofmt ```v
mut numbers := []int{ cap: 1000 } mut numbers := []int{cap: 1000}
println(numbers.len) // 0 println(numbers.len) // 0
// Now appending elements won't reallocate // Now appending elements won't reallocate
for i in 0 .. 1000 { for i in 0 .. 1000 {
numbers << i numbers << i
} }
``` ```
Note: The above code uses a [range `for`](#range-for) statement. Note: The above code uses a [range `for`](#range-for) statement.
@ -630,7 +624,7 @@ with `s := arr.str()`.
Copying the data from the array is done with `.clone()`: Copying the data from the array is done with `.clone()`:
```v nofmt ```v
nums := [1, 2, 3] nums := [1, 2, 3]
nums_copy := nums.clone() nums_copy := nums.clone()
``` ```
@ -638,7 +632,7 @@ nums_copy := nums.clone()
Arrays can be efficiently filtered and mapped with the `.filter()` and Arrays can be efficiently filtered and mapped with the `.filter()` and
`.map()` methods: `.map()` methods:
```v nofmt ```v
nums := [1, 2, 3, 4, 5, 6] nums := [1, 2, 3, 4, 5, 6]
even := nums.filter(it % 2 == 0) even := nums.filter(it % 2 == 0)
println(even) // [2, 4, 6] println(even) // [2, 4, 6]
@ -647,7 +641,6 @@ even_fn := nums.filter(fn (x int) bool {
return x % 2 == 0 return x % 2 == 0
}) })
println(even_fn) println(even_fn)
words := ['hello', 'world'] words := ['hello', 'world']
upper := words.map(it.to_upper()) upper := words.map(it.to_upper())
println(upper) // ['HELLO', 'WORLD'] println(upper) // ['HELLO', 'WORLD']
@ -665,15 +658,15 @@ println(upper_fn) // ['HELLO', 'WORLD']
Arrays can have more than one dimension. Arrays can have more than one dimension.
2d array example: 2d array example:
```v nofmt ```v
mut a := [][]int{len:2, init: []int{len:3}} mut a := [][]int{len: 2, init: []int{len: 3}}
a[0][1] = 2 a[0][1] = 2
println(a) // [[0, 2, 0], [0, 0, 0]] println(a) // [[0, 2, 0], [0, 0, 0]]
``` ```
3d array example: 3d array example:
```v nofmt ```v
mut a := [][][]int{len:2, init: [][]int{len:3, init: []int{len:2}}} mut a := [][][]int{len: 2, init: [][]int{len: 3, init: []int{len: 2}}}
a[0][1][1] = 2 a[0][1][1] = 2
println(a) // [[[0, 0], [0, 2], [0, 0]], [[0, 0], [0, 0], [0, 0]]] println(a) // [[[0, 0], [0, 2], [0, 0]], [[0, 0], [0, 0], [0, 0]]]
``` ```
@ -685,32 +678,35 @@ are used when providing a custom sorting condition.
```v nofmt ```v nofmt
mut numbers := [1, 3, 2] mut numbers := [1, 3, 2]
numbers.sort() // 1, 2, 3 numbers.sort() // 1, 2, 3
numbers.sort(a > b) // 3, 2, 1 numbers.sort(a > b) // 3, 2, 1
``` ```
```v nofmt ```v nofmt
struct User { age int name string } struct User {
age int
name string
}
mut users := [User{21, 'Bob'}, User{20, 'Zarkon'}, User{25, 'Alice'}] mut users := [User{21, 'Bob'}, User{20, 'Zarkon'}, User{25, 'Alice'}]
users.sort(a.age < b.age) // sort by User.age int field users.sort(a.age < b.age) // sort by User.age int field
users.sort(a.name > b.name) // reverse sort by User.name string field users.sort(a.name > b.name) // reverse sort by User.name string field
``` ```
### Maps ### Maps
```v nofmt ```v
mut m := map[string]int // Only maps with string keys are allowed for now mut m := map[string]int{} // Only maps with string keys are allowed for now
m['one'] = 1 m['one'] = 1
m['two'] = 2 m['two'] = 2
println(m['one']) // "1" println(m['one']) // "1"
println(m['bad_key']) // "0" println(m['bad_key']) // "0"
println('bad_key' in m) // Use `in` to detect whether such key exists println('bad_key' in m) // Use `in` to detect whether such key exists
m.delete('two') m.delete('two')
// Short syntax // Short syntax
numbers := { numbers := {
'one': 1 'one': 1
'two': 2 'two': 2
} }
``` ```
@ -835,22 +831,24 @@ println(s)
You can check the current type of a sum type using `is` and its negated form `!is`. You can check the current type of a sum type using `is` and its negated form `!is`.
You can do it either in an `if`: You can do it either in an `if`:
```v nofmt ```v
struct Abc { struct Abc {
val string val string
} }
struct Xyz { struct Xyz {
foo string foo string
} }
type Alphabet = Abc | Xyz type Alphabet = Abc | Xyz
x := Alphabet(Abc{'test'}) // sum type x := Alphabet(Abc{'test'}) // sum type
if x is Abc { if x is Abc {
// x is automatically casted to Abc and can be used here // x is automatically casted to Abc and can be used here
println(x) println(x)
} }
if x !is Abc { if x !is Abc {
println('Not Abc') println('Not Abc')
} }
``` ```
or using `match`: or using `match`:
@ -926,11 +924,13 @@ match mut x {
`in` allows to check whether an array or a map contains an element. `in` allows to check whether an array or a map contains an element.
```v nofmt ```v
nums := [1, 2, 3] nums := [1, 2, 3]
println(1 in nums) // true println(1 in nums) // true
m := {
m := {'one': 1, 'two': 2} 'one': 1
'two': 2
}
println('one' in m) // true println('one' in m) // true
``` ```
@ -966,15 +966,17 @@ V has only one looping keyword: `for`, with several forms.
#### Array `for` #### Array `for`
```v nofmt ```v
numbers := [1, 2, 3, 4, 5] numbers := [1, 2, 3, 4, 5]
for num in numbers { for num in numbers {
println(num) println(num)
} }
names := ['Sam', 'Peter'] names := ['Sam', 'Peter']
for i, name in names { for i, name in names {
println('$i) $name') // Output: 0) Sam println('$i) $name')
} // 1) Peter // Output: 0) Sam
// 1) Peter
}
``` ```
The `for value in arr` form is used for going through elements of an array. The `for value in arr` form is used for going through elements of an array.
@ -983,7 +985,7 @@ If an index is required, an alternative form `for index, value in arr` can be us
Note, that the value is read-only. Note, that the value is read-only.
If you need to modify the array while looping, you have to use indexing: If you need to modify the array while looping, you have to use indexing:
```v nofmt ```v
mut numbers := [0, 1, 2] mut numbers := [0, 1, 2]
for i, _ in numbers { for i, _ in numbers {
numbers[i]++ numbers[i]++
@ -994,26 +996,36 @@ When an identifier is just a single underscore, it is ignored.
#### Map `for` #### Map `for`
```v nofmt ```v
m := {'one':1, 'two':2} m := {
'one': 1
'two': 2
}
for key, value in m { for key, value in m {
println("$key -> $value") // Output: one -> 1 println('$key -> $value')
} // two -> 2 // Output: one -> 1
// two -> 2
}
``` ```
Either key or value can be ignored by using a single underscore as the identifier. Either key or value can be ignored by using a single underscore as the identifier.
```v nofmt ```v
m := {'one':1, 'two':2} m := {
'one': 1
'two': 2
}
// iterate over keys // iterate over keys
for key, _ in m { for key, _ in m {
println(key) // Output: one println(key)
} // two // Output: one
// two
}
// iterate over values // iterate over values
for _, value in m { for _, value in m {
println(value) // Output: 1 println(value)
} // 2 // Output: 1
// 2
}
``` ```
#### Range `for` #### Range `for`
@ -1029,7 +1041,7 @@ from `low` up to *but not including* `high`.
#### Condition `for` #### Condition `for`
```v nofmt ```v
mut sum := 0 mut sum := 0
mut i := 0 mut i := 0
for i <= 100 { for i <= 100 {
@ -1045,7 +1057,7 @@ Again, there are no parentheses surrounding the condition, and the braces are al
#### Bare `for` #### Bare `for`
```v nofmt ```v
mut num := 0 mut num := 0
for { for {
num += 2 num += 2
@ -1196,19 +1208,17 @@ fn read_log() {
## Structs ## Structs
```v nofmt ```v
struct Point { struct Point {
x int x int
y int y int
} }
mut p := Point{ mut p := Point{
x: 10 x: 10
y: 20 y: 20
} }
println(p.x) // Struct fields are accessed using a dot println(p.x) // Struct fields are accessed using a dot
// Alternative literal syntax for structs with 3 fields or fewer // Alternative literal syntax for structs with 3 fields or fewer
p = Point{10, 20} p = Point{10, 20}
assert p.x == 10 assert p.x == 10
@ -1405,19 +1415,22 @@ no need in getters/setters or properties.
### Methods ### Methods
```v nofmt ```v
struct User { struct User {
age int age int
} }
fn (u User) can_register() bool { fn (u User) can_register() bool {
return u.age > 16 return u.age > 16
} }
user := User{age: 10} user := User{
age: 10
}
println(user.can_register()) // "false" println(user.can_register()) // "false"
user2 := User{
user2 := User{age: 20} age: 20
}
println(user2.can_register()) // "true" println(user2.can_register()) // "true"
``` ```
@ -1814,20 +1827,21 @@ For more information, see [Dynamic casts](#dynamic-casts).
### Enums ### Enums
```v nofmt ```v
enum Color { enum Color {
red green blue red
green
blue
} }
mut color := Color.red mut color := Color.red
// V knows that `color` is a `Color`. No need to use `color = Color.green` here. // V knows that `color` is a `Color`. No need to use `color = Color.green` here.
color = .green color = .green
println(color) // "green" println(color) // "green"
match color { match color {
.red { println('the color was red') } .red { println('the color was red') }
.green { println('the color was green') } .green { println('the color was green') }
.blue { println('the color was blue') } .blue { println('the color was blue') }
} }
``` ```
@ -2092,7 +2106,7 @@ 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, In case of an error, that value would be assigned instead,
so it must have the same type as the content of the `Option` being handled. so it must have the same type as the content of the `Option` being handled.
```v nofmt ```v
fn do_something(s string) ?string { fn do_something(s string) ?string {
if s == 'foo' { if s == 'foo' {
return 'foo' return 'foo'
@ -2153,7 +2167,7 @@ runtime parameter types. This is why `find_by_id` can omit `<T>`, because the
receiver argument `r` uses a generic type `T`. receiver argument `r` uses a generic type `T`.
Another example: Another example:
```v nofmt ```v
fn compare<T>(a T, b T) int { fn compare<T>(a T, b T) int {
if a < b { if a < b {
return -1 return -1
@ -2168,12 +2182,10 @@ fn compare<T>(a T, b T) int {
println(compare(1, 0)) // Outputs: 1 println(compare(1, 0)) // Outputs: 1
println(compare(1, 1)) // 0 println(compare(1, 1)) // 0
println(compare(1, 2)) // -1 println(compare(1, 2)) // -1
// compare<string> // compare<string>
println(compare('1', '0')) // Outputs: 1 println(compare('1', '0')) // Outputs: 1
println(compare('1', '1')) // 0 println(compare('1', '1')) // 0
println(compare('1', '2')) // -1 println(compare('1', '2')) // -1
// compare<f64> // compare<f64>
println(compare(1.1, 1.0)) // Outputs: 1 println(compare(1.1, 1.0)) // Outputs: 1
println(compare(1.1, 1.1)) // 0 println(compare(1.1, 1.1)) // 0
@ -2227,8 +2239,8 @@ Channels can be buffered or unbuffered and it is possible to `select` from multi
Channels have the type `chan objtype`. An optional buffer length can specified as the `cap` property Channels have the type `chan objtype`. An optional buffer length can specified as the `cap` property
in the declaration: in the declaration:
```v nofmt ```v
ch := chan int{} // unbuffered - "synchronous" ch := chan int{} // unbuffered - "synchronous"
ch2 := chan f64{cap: 100} // buffer length 100 ch2 := chan f64{cap: 100} // buffer length 100
``` ```
@ -2251,18 +2263,17 @@ fn main() {
Objects can be pushed to channels using the arrow operator. The same operator can be used to Objects can be pushed to channels using the arrow operator. The same operator can be used to
pop objects from the other end: pop objects from the other end:
```v nofmt ```v
import sync
mut ch := chan int{} mut ch := chan int{}
mut ch2 := chan f64{} mut ch2 := chan f64{}
n := 5 n := 5
x := 7.3 x := 7.3
ch <- n // push ch <- n
// push
ch2 <- x ch2 <- x
mut y := f64(0.0) mut y := f64(0.0)
m := <-ch // pop creating new variable m := <-ch // pop creating new variable
y = <-ch2 // pop into existing variable y = <-ch2 // pop into existing variable
``` ```
A channel can be closed to indicate that no further objects can be pushed. Any attempt A channel can be closed to indicate that no further objects can be pushed. Any attempt
@ -2337,19 +2348,19 @@ if select {
#### Special Channel Features #### Special Channel Features
For special purposes there are some builtin properties and methods: For special purposes there are some builtin properties and methods:
```v nofmt ```v
struct Abc{x int} struct Abc {
x int
}
a := 2.13 a := 2.13
mut ch := chan f64{} mut ch := chan f64{}
res := ch.try_push(a) // try to perform `ch <- a`
res := ch.try_push(a) // try to perform `ch <- a`
println(res) println(res)
l := ch.len // number of elements in queue l := ch.len // number of elements in queue
c := ch.cap // maximum queue length c := ch.cap // maximum queue length
println(l) println(l)
println(c) println(c)
// mut b := Abc{} // mut b := Abc{}
// mut ch2 := chan f64{} // mut ch2 := chan f64{}
// res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2 // res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2
@ -2522,7 +2533,7 @@ Python, Go, or Java, except there's no heavy GC tracing everything or expensive
each object. each object.
For developers willing to have more low level control, autofree can be disabled with For developers willing to have more low level control, autofree can be disabled with
`-manualfree`, or by adding a `[manualfree]` on each function that wants manage its `-manualfree`, or by adding a `[manualfree]` on each function that wants manage its
memory manually. memory manually.
Note: right now autofree is hidden behind the -autofree flag. It will be enabled by Note: right now autofree is hidden behind the -autofree flag. It will be enabled by
@ -2588,36 +2599,45 @@ V's ORM provides a number of benefits:
- Readability and simplicity. (You don't need to manually parse the results of a query and - Readability and simplicity. (You don't need to manually parse the results of a query and
then manually construct objects from the parsed results.) then manually construct objects from the parsed results.)
```v nofmt ```v
import sqlite import sqlite
struct Customer { // struct name has to be the same as the table name (for now)
id int // a field named `id` of integer type must be the first field struct Customer {
name string // struct name has to be the same as the table name (for now)
nr_orders int id int // a field named `id` of integer type must be the first field
country string name string
nr_orders int
country string
} }
db := sqlite.connect('customers.db')? db := sqlite.connect('customers.db') ?
// select count(*) from Customer // select count(*) from Customer
nr_customers := sql db { select count from Customer } nr_customers := sql db {
select count from Customer
}
println('number of all customers: $nr_customers') println('number of all customers: $nr_customers')
// V syntax can be used to build queries // V syntax can be used to build queries
// db.select returns an array // db.select returns an array
uk_customers := sql db { select from Customer where country == 'uk' && nr_orders > 0 } uk_customers := sql db {
select from Customer where country == 'uk' && nr_orders > 0
}
println(uk_customers.len) println(uk_customers.len)
for customer in uk_customers { for customer in uk_customers {
println('$customer.id - $customer.name') println('$customer.id - $customer.name')
} }
// by adding `limit 1` we tell V that there will be only one object // by adding `limit 1` we tell V that there will be only one object
customer := sql db { select from Customer where id == 1 limit 1 } customer := sql db {
select from Customer where id == 1 limit 1
}
println('$customer.id - $customer.name') println('$customer.id - $customer.name')
// insert a new customer // insert a new customer
new_customer := Customer{name: 'Bob', nr_orders: 10} new_customer := Customer{
sql db { insert new_customer into Customer } name: 'Bob'
nr_orders: 10
}
sql db {
insert new_customer into Customer
}
``` ```
For more examples, see <a href='https://github.com/vlang/v/blob/master/vlib/orm/orm_test.v'>vlib/orm/orm_test.v</a>. For more examples, see <a href='https://github.com/vlang/v/blob/master/vlib/orm/orm_test.v'>vlib/orm/orm_test.v</a>.