สามารถมีพารามิเตอร์เสริมได้หรือไม่ หรือฉันสามารถกำหนดฟังก์ชั่นสองอย่างที่มีชื่อเดียวกันและจำนวนอาร์กิวเมนต์ต่างกันได้หรือไม่
สามารถมีพารามิเตอร์เสริมได้หรือไม่ หรือฉันสามารถกำหนดฟังก์ชั่นสองอย่างที่มีชื่อเดียวกันและจำนวนอาร์กิวเมนต์ต่างกันได้หรือไม่
คำตอบ:
Go ไม่มีพารามิเตอร์ที่เป็นทางเลือกและไม่รองรับการโอเวอร์โหลดวิธี :
วิธีการจัดส่งจะง่ายขึ้นถ้าไม่จำเป็นต้องทำการจับคู่ประเภทเช่นกัน ประสบการณ์กับภาษาอื่น ๆ บอกเราว่าการใช้วิธีการที่หลากหลายด้วยชื่อเดียวกัน แต่ลายเซ็นที่แตกต่างกันนั้นมีประโยชน์ในบางครั้ง แต่อาจทำให้สับสนและเปราะบางในทางปฏิบัติ การจับคู่ตามชื่อเท่านั้นและต้องการความสอดคล้องในประเภทคือการตัดสินใจที่ง่ายขึ้นที่สำคัญในระบบประเภทของ Go
make
กรณีพิเศษแล้ว? หรือว่ามันไม่ได้ถูกนำมาใช้เป็นฟังก์ชั่นจริงๆ ...
make
เป็นโครงสร้างภาษาและไม่มีการใช้กฎที่กล่าวถึงข้างต้น ดูคำถามที่เกี่ยวข้องนี้
range
เป็นกรณีเดียวกับmake
ในความรู้สึกว่า
วิธีที่ดีในการทำสิ่งต่าง ๆ เช่นพารามิเตอร์ทางเลือกคือการใช้ตัวแปรแบบ Arad ฟังก์ชั่นได้รับชิ้นส่วนของประเภทที่คุณระบุ
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
params
เป็นส่วนหนึ่งของ ints
คุณสามารถใช้ struct ซึ่งรวมถึงพารามิเตอร์:
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})
สำหรับพลจำนวนมากที่อาจเกิดขึ้นของพารามิเตอร์ที่ไม่จำเป็นเป็นสำนวนที่ดีคือการใช้ตัวเลือกฟังก์ชั่น
สำหรับประเภทของคุณ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
หากคุณต้องการพารามิเตอร์บังคับให้เพิ่มเป็นอาร์กิวเมนต์แรกของการสร้างก่อน options
variadic
ประโยชน์หลักของสำนวนฟังก์ชั่นคือ:
เทคนิคนี้จะได้รับการประกาศเกียรติคุณจากร็อบหอกและยังแสดงให้เห็นโดยเดฟเชนีย์
func()
ถ้าจำเป็นกว่าที่โค้งสมองของฉันรอบวิธีนี้ เมื่อใดก็ตามที่ฉันต้องใช้วิธีการนี้เช่นห้องสมุด Echo ฉันพบว่าสมองของฉันติดอยู่ในรูกระต่ายของนามธรรม #fwiw
ไม่สนับสนุนพารามิเตอร์ทางเลือกหรือฟังก์ชั่นการโอเวอร์โหลดของฟังก์ชั่นรองรับใน Go Go สนับสนุนพารามิเตอร์จำนวนตัวแปร: กำลังส่งอาร์กิวเมนต์ไปยัง ... พารามิเตอร์
ไม่ - ไม่ ต่อไปสำหรับ C ++ โปรแกรมเมอร์เอกสาร
Go ไม่สนับสนุนการโอเวอร์โหลดฟังก์ชั่นและไม่รองรับโอเปอเรเตอร์ที่ผู้ใช้กำหนด
ฉันไม่พบคำสั่งที่ชัดเจนพอ ๆ กันว่าไม่สนับสนุนพารามิเตอร์ที่เป็นทางเลือก แต่ไม่สนับสนุนเช่นกัน
คุณสามารถสรุปแค็ปซูลนี้ได้เป็นอย่างดีใน func คล้ายกับที่อยู่ด้านล่าง
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 และ arad variadic ด้วยวิธีนี้ฉันไม่จำเป็นต้องเปลี่ยนอินเทอร์เฟซที่มีอยู่ซึ่งถูกใช้โดยบริการหลายอย่างและบริการของฉันก็สามารถส่งผ่านพารามิเตอร์เพิ่มเติมได้ตามต้องการ โค้ดตัวอย่างในสนามเด็กเล่น golang: https://play.golang.org/p/G668FA97Nu
ภาษาโกไม่สนับสนุนการใช้วิธีการมากไป แต่คุณสามารถใช้ตัวแปรแบบหลากหลายเช่นเดียวกับพารามิเตอร์ทางเลือกคุณยังสามารถใช้อินเตอร์เฟส {} เป็นพารามิเตอร์ได้ แต่ไม่ใช่ตัวเลือกที่ดี
ฉันช้าไปหน่อย แต่ถ้าคุณชอบส่วนต่อประสานที่คล่องแคล่วคุณอาจออกแบบ setters ของคุณสำหรับการโทรที่ถูกล่ามโซ่เช่นนี้:
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
ตัวแปรและ zeroingอย่างไรก็ตามมีข้อได้เปรียบเล็กน้อยที่เป็นไปได้การเรียกใช้ฟังก์ชั่นประเภทนี้น่าจะง่ายกว่าสำหรับคอมไพเลอร์ที่จะแทรกเข้ามา แต่ฉันไม่ใช่ผู้เชี่ยวชาญ
คุณสามารถส่งพารามิเตอร์ที่กำหนดชื่อเองได้โดยใช้แผนที่
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})
}
ความเป็นไปได้อีกอย่างก็คือการใช้โครงสร้างที่มีเขตข้อมูลเพื่อระบุว่ามันถูกต้องหรือไม่ ประเภท null จาก sql เช่นNullStringสะดวก เป็นการดีที่ไม่จำเป็นต้องกำหนดประเภทของคุณเอง แต่ในกรณีที่คุณต้องการชนิดข้อมูลที่กำหนดเองคุณสามารถทำตามรูปแบบเดียวกันได้เสมอ ฉันคิดว่าตัวเลือก ness นั้นชัดเจนจากนิยามฟังก์ชันและมีโค้ดหรือความพยายามน้อยมาก
ตัวอย่างเช่น:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}