顺序执行模块代码处理技巧——error转panic

问题描述

完成某项具体工作时, 通常会将工作拆分成多个子模块, 然后将各个子模块进行有效组合即可解决问题. 当各个子模块具有严格依赖关系时, 通常对每一个子模块的运行结果进行判断, 代码结构如下: 

func processBigProgram() (da interface{}, err error) {
	data, err := f1()
	if err != nil {
	    return data, err
	}
	data, err = f2()
	if err != nil {
	    return data, err
	}
	data, err = f3()
	if err != nil {
	    return data, err
	}
	data, err = f4()
	if err != nil {
	    return data, err
	}
	return
}

不难看出完成该工作只需要依次执行f1、f2、f3、f4. 但是每个函数(子模块)执行完成之后都对err进行判断, 使得简单的主线被掩藏. 代码行数被放大了4倍. 当然也可以将判断与函数执行放到一行, 但是并没有解决任何问题.

尝试解决

各个子模块执行完成之后需要判定执行过程中是否发生err, 若err!=nil, 返回相应结果. 代码功能完全相同, 因此可以将该部分代码提取为函数proxyFunc, 当proxyFunc执行有err时通过发送panic, 中断程序继续向下执行. 最后通过defer接收panic, 解析最终返回结果. 完整实现代码如下. 通过proxyFunc处理之后, test()主脉络更清晰, 代码更容易阅读, 也更整洁. 

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"os"
	"time"
)

type result struct {
	data interface{}
	errV error
}

type Music struct {
	name string
	id   int
}

func main() {
	res := test()
	if res == nil {
		fmt.Println("result is nil")
		os.Exit(1)
	}
	if data, ok := res.(Music); !ok {
		fmt.Println("result is not music")
		os.Exit(1)
	} else {
		fmt.Println(data)
	}
}

func test() (data interface{}) {
	defer func() {
		if re := recover(); re != nil {
			if r, ok := re.(result); ok {
				b, _ := json.Marshal(r)
				fmt.Println("system error,data:", string(b))
				data = r
			} else {
				fmt.Println("other panic process...")
			}
		}
	}()

	var music = Music{name: "origin", id: 0}

	music = proxyFunc(test1, validateTrue, music).(Music)
	music = proxyFunc(test2, validateTrue, music).(Music)
	music = proxyFunc(test3, validateTrue, music).(Music)
	music = proxyFunc(test4, validateTrue, music).(Music)
	fmt.Println("run success!!!!!")

	return music
}

func proxyFunc(f func(param ...interface{}) (data interface{}, err error), validate func(data interface{}, err error), param ...interface{}) (res interface{}) {
	data, err := f(param)
	validate(data, err)
	return data
}

func validateTrue(data interface{}, err error) {
	if err != nil {
		panic(result{data: data, errV: err})
	}
}

func test1(param ...interface{}) (data interface{}, err error) {
	rand.Seed(time.Now().UnixNano())
	var music = Music{name: "test1", id: 1}
	if rand.Int31n(12)%3 == 0 {
		err = errors.New("test1 error")
		fmt.Println("test1 error")
		return data, err
	}
	fmt.Println("test1 success")
	return music, nil
}

func test2(param ...interface{}) (data interface{}, err error) {
	rand.Seed(time.Now().UnixNano())
	var music = Music{name: "test2", id: 2}
	if rand.Int31n(12)%3 == 0 {
		err = errors.New("test3 error")
		fmt.Println("test2 error")
		return data, err
	}
	fmt.Println("test2 success")
	return music, nil
}

func test3(param ...interface{}) (data interface{}, err error) {
	rand.Seed(time.Now().UnixNano())
	var music = Music{name: "test3", id: 3}
	if rand.Int31n(12)%3 == 0 {
		err = errors.New("test3 error")
		fmt.Println("test3 error")
		return data, err
	}
	fmt.Println("test3 success")
	return music, nil
}

func test4(param ...interface{}) (data interface{}, err error) {
	rand.Seed(time.Now().UnixNano())
	var music = Music{name: "test4", id: 4}
	if rand.Int31n(12)%3 == 0 {
		err = errors.New("test4 error")
		fmt.Println("test4 error")
		return data, err
	}
	fmt.Println("test4 success")
	return music, nil
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值