• 爱上开源之golang入门至实战第四章函数(Func)(四)


    爱上开源之golang入门至实战第四章函数(Func)(四)

    4.4.4 命名的返回值

     

    GO语言函数声明的返回值除了支持多个返回值这个不同于其他语言的特点;还支持返回值命名的特点;来看一个例子

    1. func Fibonacci(a int) int {
    2. if a == 0 {
    3. return 0
    4. }
    5. if a == 1 {
    6. return 1
    7. }
    8. return Fibonacci(a-2) + Fibonacci(a-1)
    9. }

    1. a := 3
    2. fmt.Printf("Fibonacci(%d)=%d \n", a, Fibonacci(a))
    3. a = 4
    4. fmt.Printf("Fibonacci(%d)=%d \n", a, Fibonacci(a))
    5. a = 5
    6. fmt.Printf("Fibonacci(%d)=%d \n", a, Fibonacci(a))
    7. ==== OUTPUT ====
    8. Fibonacci(3)=2
    9. Fibonacci(4)=3
    10. Fibonacci(5)=5

    这是一个很普通的函数, 函数计算斐波那契数列(Fibonacci)的元素对应值;在这个函数里,返回值只有一个int的值,我们可以将上述Fibonacci函数改写为带命名的返回值的方式

    1. func FibonacciA(a int) (n int) {
    2. if a <= 0 {
    3. n = 0
    4. }
    5. if a == 1 {
    6. n = 1
    7. }
    8. if a >= 2 {
    9. n = Fibonacci(a-2) + Fibonacci(a-1)
    10. }
    11. return
    12. }

    使用命名返回值的方式的时候;可以把命名返回值作为结果返回形参(result parameters)的形式;简而言之就是完全可以把命名返回值当作是一个参数这样的方式来使用;和传入参数的方式一样, 基础类型都是值传递;指针类型参数都是以引用传递;当出现命名方悔之,命名返回值被初始化为相应类型的零值,当需要返回的时候,我们只需要一 条简单的不带参数的return语句。需要注意的是,即使只有一个命名返回值,在定义的时候也需要使用 () 括起来:比如例子里出现的就是一个返回值的(n int);

    上面的例子,可以改写为

    1. func FibonacciB(a int) (n int) {
    2. if a <= 0 {
    3. n = 0
    4. return
    5. }
    6. if a == 1 {
    7. n = 1
    8. return
    9. }
    10. n = Fibonacci(a-2) + Fibonacci(a-1)
    11. return
    12. }

    下一个例子,我们进一步升级上面的

    我们可以通过斐波那契数列(Fibonacci)的函数, 目前的斐波那契数列(Fibonacci)返回是对于元素的值, 现在升级一下,返回整个队列的所有元素。

    1. func FibonacciC(a int) (n []int) {
    2. if a <= 0 {
    3. n = append(n, 0)
    4. return
    5. }
    6. if a == 1 {
    7. n = append(FibonacciC(a-1), 1)
    8. return
    9. }
    10. n = append(FibonacciC(a - 1))
    11. n = append(n, n[len(n)-1]+n[len(n)-2])
    12. return
    13. }
    1. a := 0
    2. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    3. a = 1
    4. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    5. a = 2
    6. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    7. a = 3
    8. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    9. a = 4
    10. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    11. a = 5
    12. fmt.Printf("Fibonacci(%d)=%v \n", a, FibonacciC(a))
    13. ==== OUTPUT ====
    14. Fibonacci(0)=[0]
    15. Fibonacci(1)=[0 1]
    16. Fibonacci(2)=[0 1 1]
    17. Fibonacci(3)=[0 1 1 2]
    18. Fibonacci(4)=[0 1 1 2 3]
    19. Fibonacci(5)=[0 1 1 2 3 5]
    可以看到这个列子就能够充分看到带命名的返回参数,所带来的语言之美,不仅仅是省略了一个返回值的定义的过程,这里的返回值和参数一样的性质,值传递,还是引用传递,Go适合于较低层的服务的实现,恰恰就是这些特性非常符合低层服务的编程习惯。 再来升级一下咱们的例子斐波那契数列(Fibonacci)的函数, 关于Error的应用, 
    1. func FibonacciD(a int) (n []int, err error) {
    2. if a < 0 {
    3. err = errors.New("illegal Argument")
    4. return
    5. }
    6. if a == 0 {
    7. n = append(n, 0)
    8. return
    9. }
    10. if a == 1 {
    11. n = append(FibonacciC(a-1), 1)
    12. return
    13. }
    14. n = append(FibonacciC(a - 1))
    15. n = append(n, n[len(n)-1]+n[len(n)-2])
    16. return
    17. }
    1. a := 0
    2. if n, err := FibonacciD(a); err == nil {
    3. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    4. } else {
    5. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    6. }
    7. a = 1
    8. if n, err := FibonacciD(a); err == nil {
    9. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    10. } else {
    11. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    12. }
    13. a = 2
    14. if n, err := FibonacciD(a); err == nil {
    15. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    16. } else {
    17. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    18. }
    19. a = 3
    20. if n, err := FibonacciD(a); err == nil {
    21. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    22. } else {
    23. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    24. }
    25. a = 4
    26. if n, err := FibonacciD(a); err == nil {
    27. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    28. } else {
    29. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    30. }
    31. a = 5
    32. if n, err := FibonacciD(a); err == nil {
    33. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    34. } else {
    35. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    36. }
    37. a = -1
    38. if n, err := FibonacciD(a); err == nil {
    39. fmt.Printf("Fibonacci(%d)=%v \n", a, n)
    40. } else {
    41. fmt.Printf("Fibonacci(%d)=%v \n", a, err)
    42. }
    43. ==== OUTPUT ====
    44. Fibonacci(0)=[0]
    45. Fibonacci(1)=[0 1]
    46. Fibonacci(2)=[0 1 1]
    47. Fibonacci(3)=[0 1 1 2]
    48. Fibonacci(4)=[0 1 1 2 3]
    49. Fibonacci(5)=[0 1 1 2 3 5]
    50. Fibonacci(-1)=illegal Argument

     

     

    在Go里,没有Java语言里那么强大方便的Exception Stack的处理机制,Java的Exception Stack的处理机制非常方便的对Exception进行处理,只要是熟悉Exception机制,就可以通过Throw Exception和Catch Exception来对Exception进行处理, 虽然方便,但是由于Expceptoin Stack毕竟是以内存Stack的模式来保持的,所以不管是在内存损耗,还是性能损耗上,还是存在损耗的,虽然JAVA JVM一直在优化,但机制如此,不管如何优化损耗依然存在,这就是以往JAVA程序员在谈到性能优化的时候,关于exception方面的优化,也可以提出很多的条目来就是如此。 在Go语言里没有这个Exception Stack,对于JAVA语言诞生而言,其就是关注与服务器端的应用业务, 而Go的诞生是来作为拥抱云原生的服务组件,可能exceptoin的损耗反馈到业务系统里可以忽略不计,但是对于面向低层的服务,这些损耗不能不计。 Exception stack的设计是面向应用的,JAVA体系很多架构(EJB,Spring,MyBatis)就明确区分了系统异常和应用异常。都是基于Excepition Stack的,

    对于Go语言来说,也可以通过应用框架做到这样的效果,但是对于Go语言的本身而言,实际上是性能考虑和应用考虑的权衡选择。并不是像很多Go初学者而言,不支持。Go里完全可以通过defer/recover来实现。只是这个明显是应用架构需要关心的东西, 就不需要放在go的语言架构上支持了。比较对于Go所面对的大多数场景,性能上的优秀是考虑的要点。

  • 相关阅读:
    1.QML Hello world
    阿里巴巴中国站item_search_img按图搜索1688商品(拍立淘) API 返回值说明
    【ML04】Multiple Variable Linear Regression
    王道考研计算机网络——传输层
    IFoerster IsoSDK FoxSDK Crack-2022
    什么品牌的台灯适合学生用?视力专家推荐的护眼台灯
    深度解读F5:从企业级负载均衡到云原生应用服务
    gorm 自定义时间、字符串数组类型
    net.schmizz.sshj.DefaultConfig Illegal key size问题,NIFI部分版本因此无法正常启动
    Java锁常见面试题
  • 原文地址:https://blog.csdn.net/inthirties/article/details/126478290