golang给函数参数设置默认值的几种方式小结(函数参数默认值

目录
  • 前言
  • 强制改变
  • 使用可变参数语法糖
  • 利用结构体的config
  • 转换函数的全部参数
  • 补充知识:Golang中设置函数默认参数的优雅实现
  • 总结

前言

这个问题相当麻烦,根据golang-nuts/google groups中的这篇文章,golang现在与将来都不会支持参数默认值。Go始终在使得自己变得尽可能的简单,而增加这种额外的支持会使parser变得更复杂。

设置参数值的好处:

  • 可以缺省部分参数。
  • 可以提供一种默认的,行之有效的配置。

但是参考资料中提到了几种实现默认值的方法:

强制改变

// Both parameters are optional, use empty string for default value
func Concat1(a string, b int) string {
  if a == "" {
    a = "default-a"
  }
  if b == 0 {
    b = 5
  }

  return fmt.Sprintf("%s%d", a, b)
}

go的一大特点就是所有的变量都必须经过初始化。那如果在函数内部读取到参数值为初始化值,即可进行对应的操作。 但是这种方法无法解决设置参数默认值时所经常应对的场景,即参数缺省问题。

使用可变参数语法糖

// a is required, b is optional.
// Only the first value in b_optional will be used.
func Concat2(a string, b_optional ...int) string {
  b := 5
  if len(b_optional) > 0 {
    b = b_optional[0]
  }

  return fmt.Sprintf("%s%d", a, b)
}

上述方法中,a是必须的,而b是可选的。 此时b的默认值时5,如果b_optional中存在数据,则将其读取。

利用结构体的config

// A declarative default value syntax
// Empty values will be replaced with defaults
type Parameters struct {
  A string `default:"default-a"` // this only works with strings
  B string // default is 5
}

func Concat3(prm Parameters) string {
  typ := reflect.TypeOf(prm)

  if prm.A == "" {
    f, _ := typ.FieldByName("A")
    prm.A = f.Tag.Get("default")
  }

  if prm.B == 0 {
    prm.B = 5
  }

  return fmt.Sprintf("%s%d", prm.A, prm.B)
}

虽然也能做到缺省参数(如果不设置A属性,则该属性将被默认初始化),但是这种方式只对字符串管用。

转换函数的全部参数

func Concat4(args ...interface{}) string {
  a := "default-a"
  b := 5

  for _, arg := range args {
    switch t := arg.(type) {
      case string:
        a = t
      case int:
        b = t
      default:
        panic("Unknown argument")
    }
  }

  return fmt.Sprintf("%s%d", a, b)
}

相当泛用的方法,但是对于不同的类型就不可行了。

补充知识:Golang中设置函数默认参数的优雅实现

在Golang中,我们经常碰到要设置一个函数的默认值,或者说我定义了参数值,但是又不想传递值,这个在python或php一类的语言中很好实现,但Golang中好像这种方法又不行。今天在看Grpc源码时,发现了一个方法可以很优雅的实现,叫做 Functional Options Patter.通过定义函数的方式来实现

比如我们以如下的构造函数为例说明下,用这个的好处

func NewClient(address string,timeout,trynums int){}

如果我们要实例化这个函数,timeout,trynums这个是必须要传的,那如果我不想传呢,一般可能是通过传对象(struct,map)或定义多个func,感觉都不太方便。

func NewClient(address string){}
func NewClientNoTimeout(address string,trynums int){}

另一种传一个对象

type Options struct{
    timeout int,
    trynums int
}
func NewClient(address string,opts Options){}

用对象的形式,还得检查参数的合法性。比如传递了不存在的参数等。

那么,我们看下用Functional Options Patter的方式,我写了一个简单的例子。

package main

import "fmt"

//如何向func传递默认值

type dialOption struct {
    Username string
    Password string
    Service  string
}

type DialOption interface {
    apply(*dialOption)
}

type funcOption struct {
    f func(*dialOption)
}

func(fdo *funcOption) apply(do *dialOption){
     fdo.f(do)
}

func newFuncOption(f func(*dialOption))*funcOption{
    return &funcOption{
        f:f,
    }
}

func withUserName(s string) DialOption{
    return  newFuncOption(func(o *dialOption){
        o.Username = s
    })
}

func withPasswordd(s string) DialOption{
    return  newFuncOption(func(o *dialOption){
        o.Password = s
    })
}

func withService(s string) DialOption{
    return  newFuncOption(func(o *dialOption){
        o.Service = s
    })
}

//默认参数
func defaultOptions() dialOption{
    return dialOption{
        Service:"test",
    }
}

type clientConn struct {
    timeout int
    dopts dialOption
}

func NewClient(address string, opts ...DialOption){
    cc :=&clientConn{
        timeout:30,
        dopts:defaultOptions(),
    }
    //循环调用opts
    for _,opt := range opts {
        opt.apply(&cc.dopts)
    }

    fmt.Printf("%+v",cc.dopts)
}

func main(){
    NewClient("127.0.0.1",withPasswordd("654321"),withService("habox"))
    NewClient("127.0.0.1",withService("habox"))
}

实例化时,通过func的方式来传递参数,也可以定义一些默认参数。如果以后要加,只需要更改很少的代码。

而且,这种方式也不会传递不相关的参数,因为参数都在通过func的方式来修改的。

唯一不好的地方可能是代码量相应的增加了。但是为了更优雅,这种做法还是值得的。

总结

到此这篇关于golang给函数参数设置默认值的文章就介绍到这了,更多相关golang函数参数设置默认值内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang struct扩展函数参数命名警告解决方法

    今天在使用VSCode编写golang代码时,定义一个struct,扩展几个方法,如下: package storage import ( "fmt" "github.com/zsy619/gcommon" ) //ChunkFooter 块Footer type ChunkFooter struct { ChunkDataTotalSize int } //NewChunkFooter 创建一个ChunkFooter func NewChunkFooter(chu

  • golang给函数参数设置默认值的几种方式小结(函数参数默认值

    目录 前言 强制改变 使用可变参数语法糖 利用结构体的config 转换函数的全部参数 补充知识:Golang中设置函数默认参数的优雅实现 总结 前言 这个问题相当麻烦,根据golang-nuts/google groups中的这篇文章,golang现在与将来都不会支持参数默认值.Go始终在使得自己变得尽可能的简单,而增加这种额外的支持会使parser变得更复杂. 设置参数值的好处: 可以缺省部分参数. 可以提供一种默认的,行之有效的配置. 但是参考资料中提到了几种实现默认值的方法: 强制改变

  • TensorFlow设置日志级别的几种方式小结

    TensorFlow中的log共有INFO.WARN.ERROR.FATAL 4种级别.有以下几种设置方式. 1. 通过设置环境变量控制log级别 可以通过环境变量TF_CPP_MIN_LOG_LEVEL进行设置,TF_CPP_MIN_LOG_LEVEL的不同值的含义分别如下: Level Level for Humans Level Description 0 DEBUG all messages are logged (Default) 1 INFO INFO messages are no

  • Python判断Nan值的五种方式小结

    目录 Python判断Nan值方式小结 numpy判断 Math判断 Pandas判断 判断是否等于自身 Nan不属于任何取值区间 python的nan处理 定义nan的方法 常见的计算结果为nan的情况 Python判断Nan值方式小结 numpy判断 import numpy as np nan = float('nan') print(np.isnan(nan)) True Math判断 import math nan = float('nan') print(math.isnan(nan

  • springboot配置文件中使用${}注入值的两种方式小结

    目录 配置文件中使用${}注入值方式 在springboot中使用System.setProperty设置参数 配置文件自扫描 spring配置文件${}的用法 话不多说直接看就完事了 配置文件中使用${}注入值方式 在springboot中使用System.setProperty设置参数 user:   user-name: ${username}   age: ${age} 配置文件是这种写法,我们可以用System.setProperty来设置参数,System.setProperty相当

  • Spring RedisTemplate 批量获取值的2种方式小结

    目录 Spring RedisTemplate 批量获取值 1.利用mGet 2.利用PipeLine Java对Redis的批量操作RedisTemplate 1.背景 2.操作 3.说明 Spring RedisTemplate 批量获取值 1.利用mGet List<String> keys = new ArrayList<>(); //初始keys List<YourObject> list = this.redisTemplate.opsForValue().

  • 列举ASP.NET页面之间传递值的几种方式

    1 .列举ASP.NET 页面之间传递值的几种方式. 1).使用QueryString, 如....?id=1; response. Redirect()....  2).使用Session变量  3).使用Server.Transfer 为了在页面之间传递变量内容,ASP.NET给了我们几个选择.一种选择是使用QueryString 属性 一:QueryString. 可以使用查询字符串请求网页.ASP.NET中的QueryString访问此信息.当你加载file.html?x = y时,它解

  • 详解Python获取线程返回值的三种方式

    目录 方法一 方法二 方法三 最后的话 提到线程,你的大脑应该有这样的印象:我们可以控制它何时开始,却无法控制它何时结束,那么如何获取线程的返回值呢?今天就分享一下自己的一些做法. 方法一 使用全局变量的列表,来保存返回值 ret_values = [] def thread_func(*args):     ...     value = ...     ret_values.append(value) 选择列表的一个原因是:列表的 append() 方法是线程安全的,CPython 中,GI

  • Flowable 设置流程变量的四种方式详解

    目录 引言 1. 为什么需要流程变量 2. 流程变量的分类 3. 全局流程变量 3.1 启动时设置 3.2 通过 Task 设置 3.3 完成任务时设置 3.4 通过流程设置 4. 本地流程变量 4.1 通过 Task 设置 5. 临时流程变量 引言 在之前的文章中,松哥也有和小伙伴们使用过流程变量,然而没有和大家系统的梳理过流程变量的具体玩法以及它对应的数据表详情,今天我们就来看看 Flowable 中流程变量的详细玩法. 1. 为什么需要流程变量 首先我们来看看为什么需要流程变量. 举一个简

  • Java设置session超时的几种方式总结

    Java设置session超时的几种方式总结 1.      在web容器中设置(此处以tomcat为例) 在tomcat-5.0.28\conf\web.xml中设置,以下是tomcat 5.0中的默认配置: <!-- ==================== Default Session Configuration ================= --> <!-- You can set the default session timeout (in minutes) for

  • python执行系统命令后获取返回值的几种方式集合

    第一种情况 os.system('ps aux') 执行系统命令,没有返回值 第二种情况 result = os.popen('ps aux') res = result.read() for line in res.splitlines(): print line 执行系统命令,可以获取执行系统命令的结果 p = subprocess.Popen('ps aux',shell=True,stdout=subprocess.PIPE) out,err = p.communicate() for

随机推荐