Go가 선택적 매개 변수를 가질 수 있습니까? 아니면 같은 이름과 다른 수의 인수로 두 함수를 정의 할 수 있습니까?
Go가 선택적 매개 변수를 가질 수 있습니까? 아니면 같은 이름과 다른 수의 인수로 두 함수를 정의 할 수 있습니까?
답변:
Go에는 선택적 매개 변수가 없으며 메서드 오버로드를 지원하지 않습니다 .
형식 일치를 수행 할 필요가없는 경우 메서드 디스패치가 단순화됩니다. 다른 언어를 사용한 경험에 따르면 이름은 같지만 서명이 다른 다양한 방법을 사용하는 것이 때로는 유용하지만 실제로는 혼란스럽고 깨지기 쉽습니다. 이름 만 일치하고 유형의 일관성을 요구하는 것은 Go의 유형 시스템에서 단순화 된 주요 결정이었습니다.
make
특별한 경우입니까? 아니면 실제로 함수로 구현되지 않았
range
make
그런 의미에서 와 같은 경우 입니다
선택적 매개 변수와 같은 것을 달성하는 좋은 방법은 가변형 인수를 사용하는 것입니다. 이 함수는 실제로 지정한 유형의 슬라이스를받습니다.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
params
한 조각의 정수입니다
매개 변수가 포함 된 구조체를 사용할 수 있습니다.
type Params struct {
a, b, c int
}
func doIt(p Params) int {
return p.a + p.b + p.c
}
// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})
임의의 잠재적으로 많은 수의 선택적 매개 변수의 경우 기능 옵션 을 사용하는 것이 좋습니다 .
type의 Foobar
경우 먼저 생성자를 하나만 작성 하십시오 .
func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
fb := &Foobar{}
// ... (write initializations with default values)...
for _, op := range options{
err := op(fb)
if err != nil {
return nil, err
}
}
return fb, nil
}
여기서 각 옵션은 Foobar를 변경하는 기능입니다. 그런 다음 사용자가 다음과 같은 표준 옵션을 사용하거나 만들 수있는 편리한 방법을 제공하십시오.
func OptionReadonlyFlag(fb *Foobar) error {
fb.mutable = false
return nil
}
func OptionTemperature(t Celsius) func(*Foobar) error {
return func(fb *Foobar) error {
fb.temperature = t
return nil
}
}
간결성을 위해 옵션 유형 ( 놀이터 )에 이름을 지정할 수 있습니다 .
type OptionFoobar func(*Foobar) error
필수 매개 변수가 필요한 경우 variadic 앞에 생성자의 첫 번째 인수로 추가하십시오 options
.
기능 옵션 관용구 의 주요 이점은 다음 과 같습니다.
이 기술은 Rob Pike 가 만들었 으며 Dave Cheney 도 시연했습니다 .
func()
이 접근 방식으로 내 두뇌를 구부리는 것보다 필요한 경우 속성을 가질 수있는 값의 구조체를 전달하는 것을 훨씬 선호합니다 . 에코 라이브러리와 같이이 접근 방식을 사용해야 할 때마다 뇌가 추상화의 토끼 구멍에 갇히게됩니다. #fwiw
Go에서는 선택적 매개 변수 나 함수 오버로드가 지원되지 않습니다. Go는 다양한 수의 매개 변수를 지원합니다. 인수를 ... 매개 변수에 전달
아니요. 당 C ++ 프로그래머를위한 이동 문서,
Go는 함수 오버로딩을 지원하지 않으며 사용자 정의 연산자를 지원하지 않습니다.
선택적 매개 변수가 지원되지 않는다는 똑같이 명확한 진술을 찾을 수 없지만 지원되지 않습니다.
아래 내용과 비슷한 기능으로 이것을 꽤 잘 캡슐화 할 수 있습니다.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Println(prompt())
}
func prompt(params ...string) string {
prompt := ": "
if len(params) > 0 {
prompt = params[0]
}
reader := bufio.NewReader(os.Stdin)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return text
}
이 예에서 기본적으로 프롬프트에는 콜론과 그 앞에 공백이 있습니다. . .
:
. . . 그러나 프롬프트 기능에 매개 변수를 제공하여이를 대체 할 수 있습니다.
prompt("Input here -> ")
아래와 같은 프롬프트가 나타납니다.
Input here ->
나는 params와 variadic args의 구조를 조합하여 사용했습니다. 이 방법으로 여러 서비스에서 소비 한 기존 인터페이스를 변경할 필요가 없었으며 서비스는 필요에 따라 추가 매개 변수를 전달할 수있었습니다. golang 놀이터의 샘플 코드 : https://play.golang.org/p/G668FA97Nu
나는 조금 늦었지만 유창한 인터페이스를 좋아한다면 체인 호출에 대한 세터를 다음과 같이 디자인 할 수 있습니다.
type myType struct {
s string
a, b int
}
func New(s string, err *error) *myType {
if s == "" {
*err = errors.New(
"Mandatory argument `s` must not be empty!")
}
return &myType{s: s}
}
func (this *myType) setA (a int, err *error) *myType {
if *err == nil {
if a == 42 {
*err = errors.New("42 is not the answer!")
} else {
this.a = a
}
}
return this
}
func (this *myType) setB (b int, _ *error) *myType {
this.b = b
return this
}
그런 다음 다음과 같이 호출하십시오.
func main() {
var err error = nil
instance :=
New("hello", &err).
setA(1, &err).
setB(2, &err)
if err != nil {
fmt.Println("Failed: ", err)
} else {
fmt.Println(instance)
}
}
이것은 @Ripounet 답변에 제시된 기능 옵션 관용구 와 유사 하며 동일한 이점을 누리지 만 몇 가지 단점이 있습니다.
err
변수를 선언 하고 제로화 하는 선을 사용해야합니다.그러나 가능한 작은 이점이 있습니다.이 유형의 함수 호출은 컴파일러가 인라인하기가 더 쉽지만 실제로는 전문가가 아닙니다.
맵과 함께 임의의 명명 된 매개 변수를 전달할 수 있습니다.
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default" // optional default value
if val, ok := args["arg1"]; ok {
// value override or other action
arg1 = val.(string) // runtime panic if wrong type
}
arg2 := 123 // optional default value
if val, ok := args["arg2"]; ok {
// value override or other action
arg2 = val.(int) // runtime panic if wrong type
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
다른 가능성은 필드와 함께 유효한지 여부를 나타내는 구조체를 사용하는 것입니다. NullString 과 같은 SQL의 null 유형 이 편리합니다. 자체 유형을 정의 할 필요는 없지만 사용자 정의 데이터 유형이 필요한 경우 항상 동일한 패턴을 따를 수 있습니다. 옵션 정의는 함수 정의에서 명확하고 최소한의 추가 코드 또는 노력이 있다고 생각합니다.
예로서:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}