错误处理

内置函数和结构体

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

//内置错误接口
pub interface IError {
	msg() string //返回错误消息
	code() int //返回错误码
}
//内置的消息错误类型
pub struct Error {}

pub fn (err Error) msg() string {
	return ''
}

pub fn (err Error) code() int {
	return 0
}
//内置函数,创建一个错误,错误的类型为内置的MessageError
pub fn error(msg string) IError //抛出带消息的错误
pub fn error_with_code(msg string,code int) IError //带错误消息和错误码

错误定义

定义函数时:

返回类型前加感叹号!表示:函数可能返回正常的类型或返回错误,即 T | IError,

返回类型前加问号?表示:函数可能返回正常的类型或返回空值,即 T | none,

其实对应的类型是内置的Option类型

然后在函数代码中根据逻辑,返回空值或错误:

return none //返回空值

return error('error message')  //表示抛出错误

return error_with_code('error message',1)  //表示抛出带错误消息和错误码的错误

示例代码:

module main

// ?表示疑问,表示可能返回期望的类型,也可能返回一个空值none
pub fn return_type_or_none(x int) ?int { 
	match x {
		0 { return none }
		else { return x }
	}
}

// !表示警告,表示可能返回期望的类型,也可能返回一个错误IError
pub fn return_type_or_error(x int) !int { 
	match x {
		0 { return error('error: x can not be 0') }
		else { return x }
	}
}

fn main() {
	v1 := return_type_or_none(0) or {
		match err {
			none { 10 } //如果返回空值none,可以指定默认值
			else { panic(err) }
		}
	}
	println(v1)

	v2 := return_type_or_none(1) or {
		match err {
			none { 10 } //如果返回空值none,可以指定默认值
			else { panic(err) }
		}
	}
	println(v2)

	v3 := return_type_or_error(2) or { panic(err) }
	println(v3)

	v4 := return_type_or_error(0) or { panic(err) }
	println(v4)
}

错误处理

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

err.msg()返回错误信息,err.code()返回错误码。

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

//函数定义
fn my_fn(i int) !int {
	if i == 0 {
		return error('Not ok!') //抛出错误,err的值为Not ok!
	}
	return i //正常返回
}

fn my_fn2(i int) !(int, int) { //多返回值时,!放在括号前面
	return 1, 1
}

fn main() {
	//函数调用
	//未触发错误,不执行or代码块,返回函数的返回值
	v1 := my_fn(1) or {
		println('from 2')
		return
	}
	println(v1)
	//触发错误,执行or代码块,程序中断,报错:V panic: Not ok!
	v2 := my_fn(0) or {
		println('from 0')
		panic(err.msg()) //默认会传递err参数给or代码块,包含错误信息
	}
	println(v2)
}

也可以通过match语句来匹配不同的错误,进行错误处理:

module main

import semver

fn main() {
	semver.from('asd') or { check_error(err) }
	semver.from('') or { check_error(err) }
}

fn check_error(err IError) {
	match err { //匹配不同的错误类型,进行错误处理
		semver.InvalidVersionFormatError {
			println('wrong format')
		}
		semver.EmptyInputError {
			println('empty input')
		}
		else {
			println('unknown error')
		}
	}
}

if guard守护条件处理错误:

module main

//带空值的函数
fn my_fn(i int) ?int {
	if i == 0 {
		return none //返回空值
	}
	return i //正常返回
}

// 多返回值的函数
fn create() ?(int, string, bool) {
	return 5, 'aa', true
}

fn main() {
	// if guard expr
	if c := my_fn(2) { // if guard守护条件,调用函数时,正常返回,执行if分支
		println('$c') // 输出2
	} else {
		println('$err')
	}
	if c := my_fn(0) { // if guard守护条件,调用函数时,返回none,执行else分支
		println('$c') 
	} else {
		println('$err') // 输出none
	}

	if r1, r2, r3 := create() { // 多返回值的if guard守护条件
		println(r1)
		println(r2)
		println(r3)
	} else {
		println('$err')
	}

	// if守护条件,其实等价于
	cc := my_fn(0) or {
		println('$err')
		11
	}
	println(cc)

	// if guard的变量是可变的情况
	if mut c := my_fn(3) {
		c = 2
		println(c)
	} else {
		println('$err')
	}
}

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

module main

import os

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

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

module main

fn main() {
	exec('') or { panic('error is :$err') }
}

fn exec(stmt string) ! { //无返回值,也可抛出错误
	if stmt == '' {
		return error('stmt is null')
	}
	println(stmt)
}

返回错误码:

module main

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

fn exec(stmt string) ! {
	if stmt == '' {
		return error_with_code('stmt is null', 123) //需要带错误码
	}
	println(stmt)
}

向上抛转错误

调用函数时,可以在调用时不处理,而是向调用链的上级函数抛转错误,如果向上抛转到main主函数还没有处理错误,那么就会以panic的方式报错。

向上抛转时,上级函数的返回值必须也是对应的错误或空值,否则编译时会报错。

//函数定义
fn my_fn(i int) !int {
	if i == 0 {
		return error('Not ok') //抛出错误,err的值为Not ok
	}
	return i //正常返回
}

fn my_fn2(i int) ?int {
	if i == 0 {
		return none //返回空值
	}
	return i //正常返回
}

fn my_fn3() ?int {
	v := my_fn2(0)? //本级不处理空值,向上抛转,函数返回的错误类型必须也是?,而不能是!
	return v
}

fn main() {
	v1 := my_fn(1)! //本级不处理,向上抛转错误
	println(v1)

	v2 := my_fn2(0) or { 0 } //本级处理空值
	println(v2)

	v3 := my_fn3() or { -1 } //下级函数向上抛转,未处理的空值,必须在main中处理,否则报错
	println(v3)
}

自定义错误类型

module main

struct MyError { //组合内置的Error类型,来自定义错误类型
	Error
}

pub fn (error MyError) msg() string { //定义错误消息
	return 'my error message'
}

struct MyError2 {} //通过实现IError接口,来自定义错误类型

pub fn (error MyError2) msg() string {
	return 'my error2 message'
}

pub fn (error MyError2) code() int {
	return 11
}

pub fn my_fn(name string) !string {
	if name == '' {
		return MyError{} //抛出自定义错误
	} else {
		return name
	}
}

pub fn my_fn2(name string) !string {
	if name == '' {
		return MyError2{}
	} else {
		return name
	}
}

fn main() {
	name := ''
	// my_fn(name) or {
	// 	println(err.code())
	// 	panic(err)
	// }
	my_fn2(name) or {
		println(err.code())
		panic(err)
	}
}

最后更新于