Đi có thể có các tham số tùy chọn? Hoặc tôi chỉ có thể định nghĩa hai hàm có cùng tên và số lượng đối số khác nhau?
Đi có thể có các tham số tùy chọn? Hoặc tôi chỉ có thể định nghĩa hai hàm có cùng tên và số lượng đối số khác nhau?
Câu trả lời:
Go không có các tham số tùy chọn cũng như không hỗ trợ nạp chồng phương thức :
Công văn phương thức được đơn giản hóa nếu nó không cần phải thực hiện khớp loại. Kinh nghiệm với các ngôn ngữ khác nói với chúng tôi rằng có nhiều phương pháp có cùng tên nhưng chữ ký khác nhau đôi khi rất hữu ích nhưng nó cũng có thể gây nhầm lẫn và mong manh trong thực tế. Chỉ khớp với tên và yêu cầu tính nhất quán trong các loại là một quyết định đơn giản hóa lớn trong hệ thống loại của Go.
make
một trường hợp đặc biệt, sau đó? Hoặc nó thậm chí không thực sự được thực hiện như là một chức năng
make
là cấu trúc ngôn ngữ và các quy tắc được đề cập ở trên không áp dụng. Xem câu hỏi liên quan này .
range
là trường hợp tương tự make
, theo nghĩa đó
Một cách hay để đạt được một cái gì đó giống như các tham số tùy chọn là sử dụng args matrixdic. Hàm thực sự nhận được một lát của bất kỳ loại nào bạn chỉ định.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
params
là một lát ints
Bạn có thể sử dụng một cấu trúc bao gồm các tham số:
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})
Đối với tùy ý, có thể có số lượng lớn các tham số tùy chọn, một thành ngữ hay là sử dụng các tùy chọn Chức năng .
Đối với loại của bạn Foobar
, đầu tiên chỉ viết một hàm tạo:
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
}
trong đó mỗi tùy chọn là một chức năng làm thay đổi Foobar. Sau đó, cung cấp các cách thuận tiện cho người dùng của bạn sử dụng hoặc tạo các tùy chọn tiêu chuẩn, ví dụ:
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
}
}
Để đơn giản, bạn có thể đặt tên cho loại tùy chọn ( Sân chơi ):
type OptionFoobar func(*Foobar) error
Nếu bạn cần các tham số bắt buộc, hãy thêm chúng làm đối số đầu tiên của hàm tạo trước biến động options
.
Những lợi ích chính của thành ngữ Tùy chọn chức năng là:
Kỹ thuật này được tạo ra bởi Rob Pike và cũng được thể hiện bởi Dave Cheney .
func()
s nếu cần, hơn là uốn cong bộ não của tôi xung quanh phương pháp này. Bất cứ khi nào tôi phải sử dụng phương pháp này, chẳng hạn như với thư viện Echo, tôi thấy não của mình bị kẹt trong lỗ thỏ trừu tượng. #fwiw
Không tham số tùy chọn cũng như quá tải chức năng được hỗ trợ trong Go. Go không hỗ trợ một số lượng tham số khác nhau: Truyền đối số cho ... tham số
Không - không. Per the Go for C ++ lập trình tài liệu,
Go không hỗ trợ nạp chồng hàm và không hỗ trợ các toán tử do người dùng xác định.
Tôi không thể tìm thấy một tuyên bố rõ ràng như nhau rằng các tham số tùy chọn không được hỗ trợ, nhưng chúng cũng không được hỗ trợ.
Bạn có thể gói gọn điều này khá độc đáo trong một func tương tự như bên dưới.
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
}
Trong ví dụ này, lời nhắc theo mặc định có dấu hai chấm và khoảng trắng phía trước nó. . .
:
. . . tuy nhiên bạn có thể ghi đè lên điều đó bằng cách cung cấp một tham số cho hàm prompt.
prompt("Input here -> ")
Điều này sẽ dẫn đến một dấu nhắc như dưới đây.
Input here ->
Tôi đã kết thúc bằng cách sử dụng kết hợp một cấu trúc của params và args. Bằng cách này, tôi đã không phải thay đổi giao diện hiện có được sử dụng bởi một số dịch vụ và dịch vụ của tôi có thể vượt qua các thông số bổ sung khi cần. Mã mẫu trong sân chơi golang: https://play.golang.org/p/G668FA97Nu
Tôi hơi muộn, nhưng nếu bạn thích giao diện lưu loát, bạn có thể thiết kế setters của mình cho các cuộc gọi bị xiềng xích như thế này:
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
}
Và sau đó gọi nó như thế này:
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)
}
}
Điều này tương tự như thành ngữ Tùy chọn chức năng được trình bày trên câu trả lời @Ripounet và có cùng lợi ích nhưng có một số nhược điểm:
err
biến và zeroing nó.Tuy nhiên, có một lợi thế nhỏ có thể xảy ra, kiểu gọi hàm này sẽ dễ dàng hơn cho trình biên dịch nội tuyến nhưng tôi thực sự không phải là chuyên gia.
Bạn có thể truyền các tham số được đặt tên tùy ý bằng bản đồ.
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})
}
Một khả năng khác là sử dụng một cấu trúc có trường để cho biết nó có hợp lệ hay không. Các loại null từ sql như NullString là thuận tiện. Thật tuyệt khi không phải xác định loại của riêng bạn, nhưng trong trường hợp bạn cần một loại dữ liệu tùy chỉnh, bạn luôn có thể theo cùng một mẫu. Tôi nghĩ rằng tính năng tùy chọn rõ ràng từ định nghĩa hàm và có thêm mã hoặc nỗ lực tối thiểu.
Ví dụ:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}