错误处理

内置函数和结构体

V语言内置了以下内置错误函数和结构体,用来进行错误处理:

1. //内置错误接口
2. pub interface IError {
3. msg string //错误消息
4. code int //错误码
5. }
6. //内置错误类型,实现错误接口
7. pub struct Error {
8. pub:
9. msg  string
10. code int
11. }
12. //内置函数,创建一个错误
13. pub fn error(msg string) IError //抛出带消息的错误
14. pub fn error_with_code(msg string,code int) IError //带错误消息和错误码

错误定义

函数定义时,返回类型前面加?,表示这个函数可能返回一个错误

在函数代码中根据逻辑丢出错误:

return error(‘error message’) 或 return none 表示抛出错误

错误处理

函数调用时,使用or代码块来处理错误,默认会传递err参数给or代码块,包含错误信息,

如果return none,那么参数err的值为空

or代码块必须以:return/panic/exit/continue/break结尾

1. //函数定义
2. fn my_fn(i int) ?int {
3. if i == 0 {
4. return error('Not ok!') //抛出错误,err的值为Not ok!
5. // return Error{msg:'Not ok!', code: 1} //直接使用Error类型也可以,效果一样
6. }
7. if i == 1 {
8. return none //抛出错误,但是没有错误信息,err的值为空字符串
9. }
10. return i //正常返回
11. }

13. fn my_fn2(i int) ?(int, int) { //多返回值时,?放在括号前面
14. return 1,1
15. }

17. fn main() {
18. //函数调用
19. //触发错误,执行or代码块,程序中断,报错:V panic: Not ok!
20. v1 := my_fn(0) or {
21. println('from 0')
22. panic(err.msg) //默认会传递err参数给or代码块,包含错误信息
23. }
24. println(v1)
25. //触发错误,执行or代码块,因为是return none,所以err为空,
26. v2 := my_fn(1) or {
27. println('from 1')
28. if err.msg == '' {
29. println('err is empty')
30. }
31. return
32. }
33. println(v2)
34. //未触发错误,不执行or代码块,返回函数的返回值
35. v3 := my_fn(2) or {
36. println('from 2')
37. return
38. }
39. println(v3)
40. }

if守护条件处理错误:

1. module main

3. //带错误的函数
4. fn my_fn(i int) ?int {
5. if i == 0 {
6. return error('Not ok!') //抛出错误
7. }
8. if i == 1 {
9. return none //抛出错误
10. }
11. return i //正常返回
12. }

14. fn main() {
15. // if guard expr
16. if c := my_fn(2) { // if守护条件,调用函数时,正常返回,执行if分支
17. println('$c')
18. } else {
19. println('from else')
20. }
21. if c := my_fn(1) { // if守护条件,调用函数时,抛出错误,执行else分支
22. println('$c')
23. } else {
24. println('from else')
25. }

27. // if守护条件,其实等价于
28. cc := my_fn(22) or {
29. println('from or')
30. 0
31. }
32. println(cc)
33. }

for循环结合or代码块使用:

1. module main

3. import os

5. fn main() {
6. //for循环结合or代码块,更简洁一些
7. for line in os.read_lines(@FILE) or { panic('文件不存在') } {
8. // 报错
9. // for line in os.read_lines('不存在的文件') or { panic('文件不存在') } {
10. println(line)
11. }
12. }

若函数无返回值,仍需抛出错误,要使用?

1. module main

3. fn main() {
4. exec('') or { panic('error is :$err') }
5. }

7. fn exec(stmt string) ? { //无返回值,也可抛出错误
8. if stmt == '' {
9. return error('stmt is null')
10. }
11. println(stmt)
12. }

返回错误码

1. module main

3. fn main() {
4. exec('') or {
5. //约定的变量名err
6. panic('error text is :$err.msg;error code is $err.code')
7. }
8. }

10. fn exec(stmt string) ? {
11. if stmt == '' {
12. return error_with_code('stmt is null', 123) //需要带错误码
13. }
14. println(stmt)
15. }

向上抛转错误

1. resp := http.get(url)? //在调用函数后加上?,表示如果函数执行出现错误,当前调用层级不处理,直接向上抛转错误
2. println(resp.body)

http.get函数中,定义的返回值是:?Response

当用上面的方式调用get函数时,如果触发了错误,错误会被向上抛转给调用get函数的上级函数,

上级函数的返回类型必须也有错误处理,如果上级函数是main主函数,那么就会以panic的方式处理错误

类似以下的代码:

1. resp := http.get(url) or {
2. panic(err)
3. }
4. println(resp.body)