21 个关键字
break
, const
, continue
, defer
, else
,enum
,fn
for
go
goto
if
import
in
interface
match
module
mut
or
return
struct
,type
函数以fn
开头声明;
参数类型位于参数名之后;
不能重载;
可后声明;
1
2
3
| fn add(x int, y int) int {
return x + y
}
|
:=
是变量声明和初始化的唯一方式;
T(v)
强制转换;
只可在函数中定义变量,无全局变量;
默认为不可变量;
mut
声明可变量;
=
用来赋值;
1
2
3
4
5
| name := 'Bob' //声明并初始化不可变变量
age := 20
large_number := i64(9999999999)
mut age2 := 20 //可变量
age2 = 21 //变量赋值
|
1
2
3
4
5
6
7
8
9
10
11
12
| bool
string
i8 i16 i32 i64
u8 u16 u32 u64
byte // alias for u8
int // alias for i32
rune // alias for i32, represents a Unicode code point
f32 f64
|
字符串为只读的字节数组;
字符串数据使用 utf-8 编码;
不可变;
子字符串无需拷贝,没有额外分配空间;
+
字符串连接,左右两边均为字符串;
$v
变量引用;
1
2
3
4
5
6
7
8
9
10
| //字符串连接
age := 10
println('age = ' + age.str())
println('age = $age')
//子串
println(bobby.substr(1, 3)) // ==> "ob"
// println(bobby[1:3])
name := 'Bob'
println('Hello, $name!')
println(name.len)
|
下标 0 开始;
数组类型由数组第一个元素决定;
所有元素类型必须相同;
<<
: 将元素加入到数组末尾;
len
:数组长度;
in
操作符:元素是否在素组中;
mut
声明可变数组;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| nums := [1, 2, 3] //定义不可变数组
println(nums)
println(nums[1]) // ==> "2"
mut names := ['John'] //定义可变数组
names << 'Peter'
names << 'Sam'
// names << 10 <-- This will not compile. `names` is an array of strings.
println(names.len) // ==> "3"
println('Alex' in names) // ==> "false"
// We can also preallocate a certain amount of elements.
nr_ids := 50
mut ids := [0 ; nr_ids] // This creates an array with 50 zeroes
|
1
2
3
4
5
6
7
8
9
10
| mut m := map[string]int{} // Only maps with string keys are allowed for now
m['one'] = 1
println(m['one']) // ==> "1"
println(m['bad_key']) // ==> "0"
// TODO: implement a way to check if the key exists
numbers := { // TODO: this syntax is not implemented yet
'one': 1,
'two': 2,
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| a := 10
b := 20
if a < b {
println('$a < $b')
} else if a > b {
println('$a > $b')
} else {
println('$a == $b')
}
num := 777
// if语句表达式
s := if num % 2 == 0 {
'even'
}
else {
'odd'
}
println(s) // ==> "even"
|
只支持 for 循环;
可选择是否带 index;
for 跟判断语句代替 while;
支持无限循环;
支持 c 类型循环,循环变量默认为 mut;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| numbers := [1, 2, 3, 4, 5]
//遍历
for num in numbers {
println(num)
}
names := ['Sam', 'Peter']
for i, name in names {
println('$i) $name') // Output: 0) Sam
} // 1) Peter
//while
mut sum := 0
mut i := 0
// while
for i <= 100 {
sum += i
i++
}
//无限循环
mut num := 0
for {
num++
if num >= 10 {
break
}
}
println(num) // ==> "10"
//
for i := 0; i < 10; i++ {
println(i)
}
|
执行第一个匹配语句块;
语句块无需 break 结尾;
1
2
3
4
5
6
7
8
9
10
11
| os := 'windows'
print('V is running on ')
switch os {
case 'darwin':
println('macOS.')
case 'linux':
println('Linux.')
default:
println(os)
}
// TODO: replace with match expressions
|
结构体默认分配在栈上;
&
前缀可返回堆上结构体的指针;
不支持子类,支持嵌入;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| struct Point {
x int
y int
}
p := Point{
x: 10
y: 20
}
println(p.x) // Struct fields are accessed using a dot
pointer := &Point{10, 10} // 堆上
println(pointer.x) //
// TODO: this will be implemented later in May
struct Button {
Widget //嵌入
title string
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| struct User {
age int
}
fn (u User) can_register() bool {
return u.age > 16
}
user := User{age: 10}
println(user.can_register()) // ==> "false"
user2 := User{age: 20}
println(user2.can_register()) // ==> "true"
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| struct User {
is_registered bool
}
fn (u mut User) register() {
u.is_registered = true
}
mut user := User{}
println(user.is_registered) // ==> "false"
user.register()
println(user.is_registered) // ==> "true"
//
fn multiply_by_2(arr mut []int) {
for i := 0; i < arr.len; i++ {
arr[i] *= 2
}
}
mut nums := [1, 2, 3]
multiply_by_2(mut nums)
println(nums) // ==> "[2, 4, 6]"
|
由const
声明;
首字母必须大写;
模块级别,不能在函数内定义常量;
常量值无法改变;
支持数组、结构体等常量;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| const (
PI = 3.14
World = '世界'
)
println(PI)
println(World)
struct Color {
r int
g int
b int
}
fn (c Color) str() string { return '{$c.r, $c.g, $c.b}' }
fn rgb(r, g, b int) Color { return Color{r: r, g: g, b: b} }
const (
Numbers = [1, 2, 3]
Red = Color{r: 255, g: 0, b: 0}
Blue = rgb(0, 0, 255)
)
println(Numbers)
println(Red)
println(Blue)
|
module
关键字声明模块;
import
关键字导入模块;
不可循环导入;
编译时需用 -lib 指明模块路径;
编译时,会将所有模块静态编入可执行文件中;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| /*
cd ~/code/modules
mkdir mymodule
vim mymodule/mymodule.v
*/
// mymodule.v
module mymodule
// To export a function we have to use `pub`
pub fn say_hi() {
println('hello from mymodule!')
}
/*
You can have as many .v files in mymodule/ as you want.
Build it with v -lib ~/code/modules/mymodule.
That's it, you can now use it in your code:
*/
//main.v
module main
import mymodule
fn main() {
mymodule.say_hi()
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| struct Dog {}
struct Cat {}
fn (d Dog) speak() string {
return 'woof'
}
fn (c Cat) speak() string {
return 'meow'
}
interface Speaker {
speak() string
}
fn perform(s Speaker) {
println(s.speak())
}
dog := Dog{}
cat := Cat{}
perform(dog) // ==> "woof"
perform(cat) // ==> "meow"
|
1
2
3
4
5
6
7
8
| enum Color {
red green blue
}
mut color := Color.red
// V knows that color is a Color. No need to use `Color.green` here.
color = .green
println(color) // ==> "1" TODO: print "green"?
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| struct User {
id int
}
struct Repo {
users []User
}
fn new_repo() Repo {
user := User{id:10}
return Repo {
users: [user]
}
}
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')
}
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"
resp := http.get(url)?
println(resp.body)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| struct Repo<T> {
db DB
}
fn new_repo<T>(db DB) Repo<T> {
return Repo<T>{db: db}
}
// This is a generic function. V will generate it for every type it's used with.
fn (r Repo<T>) find_by_id(id int) ?T {
table_name := T.name // in this example getting the name of the type gives us the table name
return r.db.query_one<T>('select * from $table_name where id = ?', id)
}
db := new_db()
users_repo := new_repo<User>(db)
posts_repo := new_repo<Post>(db)
user := users_repo.find_by_id(1)?
post := posts_repo.find_by_id(1)?
|
- 和 golang 一样(2019/7 实现);
- 内置支持 json
1
2
3
4
5
6
7
8
9
10
11
12
| struct User {
name string
age int
}
data := '{ "name": "Frodo", "age": 25 }'
user := json.decode(User, data) or {
eprintln('Failed to decode json')
return
}
println(user.name)
println(user.age)
|
只能重载+
, -
, *
, /
这四个操作符;
操作符函数中不能调用其他函数;
操作符函数不能修改参数;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| struct Vec {
x int
y int
}
fn (a Vec) str() string {
return '{$a.x, $a.y}'
}
fn (a Vec) + (b Vec) Vec {
return Vec {
a.x + b.x,
a.y + b.y
}
}
fn (a Vec) - (b Vec) Vec {
return Vec {
a.x - b.x,
a.y - b.y
}
}
fn main() {
a := Vec{2, 3}
b := Vec{4, 5}
println(a + b) // ==> "{6, 8}"
println(a - b) // ==> "{-2, -2}"
}
|
1
2
3
4
5
6
7
8
9
| // hello.v
fn hello() string {
return 'Hello world'
}
// hello_test.v
fn test_hello() {
assert hello() == 'Hello world'
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #flag -lsqlite3
#include "sqlite3.h"
struct C.sqlite3
struct C.sqlite3_stmt
fn C.sqlite3_column_int(C.sqlite_stmt, int) int
fn main() {
path := 'sqlite3_users.db'
db := &C.sqlite3{}
C.sqlite3_open(path.cstr(), &db)
query := 'select count(*) from users'
stmt := &C.sqlite3_stmt{}
C.sqlite3_prepare_v2(db, query.cstr(), - 1, &stmt, 0)
C.sqlite3_step(stmt)
nr_users := C.sqlite3_column_int(res, 0)
C.sqlite3_finalize(res)
println(nr_users)
}
|
1
| v translate test.cpp and V will generate test.v:
|
1
2
3
| v -os windows .
or
v -os linux .
|