错误处理

内置函数和结构体

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. }
  12. fn my_fn2(i int) ?(int, int) { //多返回值时,?放在括号前面
  13. return 1,1
  14. }
  15. fn main() {
  16. //函数调用
  17. //触发错误,执行or代码块,程序中断,报错:V panic: Not ok!
  18. v1 := my_fn(0) or {
  19. println('from 0')
  20. panic(err.msg) //默认会传递err参数给or代码块,包含错误信息
  21. }
  22. println(v1)
  23. //触发错误,执行or代码块,因为是return none,所以err为空,
  24. v2 := my_fn(1) or {
  25. println('from 1')
  26. if err.msg == '' {
  27. println('err is empty')
  28. }
  29. return
  30. }
  31. println(v2)
  32. //未触发错误,不执行or代码块,返回函数的返回值
  33. v3 := my_fn(2) or {
  34. println('from 2')
  35. return
  36. }
  37. println(v3)
  38. }

if守护条件处理错误:

  1. module main
  2. //带错误的函数
  3. fn my_fn(i int) ?int {
  4. if i == 0 {
  5. return error('Not ok!') //抛出错误
  6. }
  7. if i == 1 {
  8. return none //抛出错误
  9. }
  10. return i //正常返回
  11. }
  12. fn main() {
  13. // if guard expr
  14. if c := my_fn(2) { // if守护条件,调用函数时,正常返回,执行if分支
  15. println('$c')
  16. } else {
  17. println('from else')
  18. }
  19. if c := my_fn(1) { // if守护条件,调用函数时,抛出错误,执行else分支
  20. println('$c')
  21. } else {
  22. println('from else')
  23. }
  24. // if守护条件,其实等价于
  25. cc := my_fn(22) or {
  26. println('from or')
  27. 0
  28. }
  29. println(cc)
  30. }

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

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

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

  1. module main
  2. fn main() {
  3. exec('') or { panic('error is :$err') }
  4. }
  5. fn exec(stmt string) ? { //无返回值,也可抛出错误
  6. if stmt == '' {
  7. return error('stmt is null')
  8. }
  9. println(stmt)
  10. }

返回错误码

  1. module main
  2. fn main() {
  3. exec('') or {
  4. //约定的变量名err
  5. panic('error text is :$err.msg;error code is $err.code')
  6. }
  7. }
  8. fn exec(stmt string) ? {
  9. if stmt == '' {
  10. return error_with_code('stmt is null', 123) //需要带错误码
  11. }
  12. println(stmt)
  13. }

向上抛转错误

  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)