Trong Go, một hàm chỉ có thể chấp nhận các đối số của các kiểu được chỉ định trong danh sách tham số trong định nghĩa hàm. Tính năng ngôn ngữ tham số đa dạng làm phức tạp điều đó một chút, nhưng nó tuân theo các quy tắc được xác định rõ.
Chữ ký hàm cho fmt.Println
là:
func Println(a ...interface{}) (n int, err error)
Theo đặc điểm ngôn ngữ ,
Tham số đến cuối cùng trong một chữ ký hàm có thể có kiểu được bắt đầu bằng .... Một hàm có tham số như vậy được gọi là variadic và có thể được gọi với 0 hoặc nhiều đối số cho tham số đó.
Điều này có nghĩa là bạn có thể chuyển Println
một danh sách các đối số interface{}
kiểu. Vì tất cả các loại đều triển khai giao diện trống, nên bạn có thể chuyển một danh sách các đối số thuộc bất kỳ loại nào, đó là cách bạn có thể gọi Println(1, "one", true)
, ví dụ, mà không bị lỗi. Xem phần "Truyền đối số cho ... tham số" của đặc tả ngôn ngữ:
giá trị được truyền là một lát cắt kiểu mới [] T với một mảng cơ bản mới có các phần tử kế tiếp là các đối số thực tế, tất cả các phần tử này phải được gán cho T.
Phần gây rắc rối cho bạn nằm ngay sau đó trong thông số kỹ thuật:
Nếu đối số cuối cùng có thể gán cho kiểu lát cắt [] T, thì nó có thể được chuyển không thay đổi làm giá trị cho tham số ... T nếu đối số được theo sau bởi .... Trong trường hợp này, không có lát cắt mới nào được tạo.
flag.Args()
là loại []string
. Kể từ T
trong Println
là interface{}
, []T
là []interface{}
. Vì vậy, câu hỏi đặt ra là liệu một giá trị lát cắt chuỗi có thể gán cho một biến của kiểu lát giao diện hay không. Bạn có thể dễ dàng kiểm tra điều đó trong mã go của mình bằng cách thử một nhiệm vụ, ví dụ:
s := []string{}
var i []interface{}
i = s
Nếu bạn cố gắng gán như vậy, trình biên dịch sẽ xuất ra thông báo lỗi sau:
cannot use s (type []string) as type []interface {} in assignment
Và đó là lý do tại sao bạn không thể sử dụng dấu chấm lửng sau một lát chuỗi làm đối số fmt.Println
. Nó không phải là một lỗi, nó đang hoạt động như dự định.
Có rất nhiều vẫn cách bạn có thể in flag.Args()
với Println
, chẳng hạn như
fmt.Println(flag.Args())
(sẽ xuất ra [elem0 elem1 ...]
, theo tài liệu gói fmt )
hoặc là
fmt.Println(strings.Join(flag.Args(), ` `)
(ví dụ sẽ xuất ra các phần tử lát chuỗi, mỗi phần tử được phân tách bằng một khoảng trắng) bằng cách sử dụng hàm Tham gia trong gói chuỗi có dấu phân tách chuỗi, chẳng hạn.
go run test.go some test flags
) và nó dường như hoạt động khi thay đổiflags.Args()...
thành justflag.Args()
(đầu ra là[some test flags]
, theo sau là dòng mới; dường như cũng hoạt động với việc đăng ký cờ thực tế). Sẽ không giả vờ để hiểu tại sao, và câu trả lời của Stephen là cách thông tin mới hơn anyway :)