2012-02-22 33 views
7

Tôi muốn tạo một chức năng của một loại nhất định. Tôi đã tìm thấy một cách để làm điều đó, nhưng phải có cách khác, sạch hơn và đẹp hơn mà không bao gồm sử dụng var. Các cách khác để khai báo chức năng english của loại Greeting là gì?Làm việc với các loại chức năng trong Go

package main 

import "fmt" 

type Greeting func(name string) string 

func (g Greeting) exclamation(name string) string { 
    return g(name) + "!" 
} 

var english = Greeting(func(name string) string { 
    return "Hello, " + name 
}) 

func main() { 
    fmt.Println(english("ANisus")) 
    fmt.Println(english.exclamation("ANisus")) 
} 

Trong ví dụ trên, tôi không thể trao đổi với var english = Greeting...english := Greeting..., cũng không phải tôi có thể loại bỏ các Greeting(func ...) và chỉ có func đứng một mình kể từ đó tôi sẽ không thể truy cập vào chấm than phương pháp.

+2

Bạn không thể xóa 'var' vì bạn đang khai báo' english' làm biến toàn cầu. – Mostafa

Trả lời

12

Nếu nhắc đến var là vấn đề chính của bạn, bạn có thể thả nó một cách dễ dàng, bằng cách thay đổi = vào :=, như thế này:

english := Greeting(func(name string) string { 
    return ("Hello, " + name); 
}) 

Nhưng bạn thậm chí không phải bỏ chức năng của bạn vào Greeting. Thông số kỹ thuật cho biết điều này về số function types:

Loại hàm biểu thị tập hợp tất cả các hàm có cùng thông số và loại kết quả.

Và đây về type identity:

Hai loại chức năng giống hệt nhau nếu họ có cùng một số thông số và giá trị kết quả, tương ứng với tham số và kết quả các loại giống hệt nhau, và một trong hai cả hai chức năng là variadic hay không Là. Thông số và tên kết quả không bắt buộc phải khớp.

Điều này có nghĩa là mỗi chức năng đều có loại chức năng riêng. Nếu hai hàm có cùng chữ ký (tham số và kiểu kết quả), chúng có chung một kiểu hàm. Bằng cách viết type Greeting func..., bạn chỉ cần đặt tên cho một loại hàm cụ thể, không định nghĩa tên mới.

Vì vậy, các mã sau đây làm việc, và tôi hy vọng thể hiện đúng cách để làm việc với các loại chức năng trong Go:

package main 

import "fmt" 

type Greeting func(name string) string 

func say(g Greeting, n string) { fmt.Println(g(n)) } 

func french(name string) string { return "Bonjour, " + name } 

func main() { 
     english := func(name string) string { return "Hello, " + name } 

     say(english, "ANisus") 
     say(french, "ANisus") 
} 

Chú ý rằng tôi cũng bỏ dấu chấm phẩy và dấu ngoặc đơn từ chức năng english của bạn. Các nhà phát triển không sử dụng các dấu chấm câu này nếu họ không phải làm như vậy.

CẬP NHẬT: Bây giờ bạn đã cung cấp mã mẫu, tôi có thể hiểu rõ vấn đề.

Vì mục đích này, mã của bạn đủ tốt và không có nhiều cách khác để thực hiện. Nếu bạn thích, bạn có thể truyền ngay trước khi gọi phương thức:

english := func(name string) string { return "Hello, " + name } 
Greeting(english).exclamation("ANisus") 

Nhưng tôi không chắc đây là cải tiến. Tôi chỉ nói rằng những gì bạn muốn làm ở đó không có vẻ là những cách khác để viết mã.

Tức là, nếu chúng tôi không muốn thay đổi loại của bạn. Ý tôi là, toàn bộ ý tưởng gọi một phương thức trên một kiểu hàm có vẻ lạ một chút. Không phải là nó sai, nhưng một chút hiếm. Một cách khác để đạt được hiệu quả tương tự theo cách thông thường hơn là thông qua một kiểu cấu trúc và có một trường cho hàm.Một cái gì đó như thế này:

package main 

import "fmt" 

type Greeting struct { 
    say func(name string) string 
} 

func newGreeting(f func(string) string) *Greeting { 
    return &Greeting{say: f} 
} 

func (g *Greeting) exclamation(name string) string { return g.say(name) + "!" } 

func main() { 
    english := &Greeting{say: func(name string) string { 
     return "Hello, " + name 
    }} 

    french := newGreeting(func(name string) string { 
     return "Bonjour, " + name 
    }) 

    fmt.Println(english.exclamation("ANisus")) 
    fmt.Println(french.exclamation("ANisus")) 
} 

Đây englishfrench hiển thị hai cách khác nhau để mã hóa những điều tương tự. Một lần nữa, tôi không nói rằng đây là giải pháp tốt hơn, nhưng một cách thông thường hơn và linh hoạt hơn để đạt được hiệu quả tương tự.

+1

Cảm ơn câu trả lời. Nhưng câu hỏi của tôi là làm thế nào để khai báo một hàm của một kiểu cụ thể. Trong ví dụ mã của bạn, bạn không bao giờ làm điều đó. Tôi đã cập nhật ví dụ của mình, và như bạn có thể nhận thấy, khi bạn thêm một phương thức vào kiểu, bạn không thể truy cập nó, trừ khi bạn làm phần 'Chào mừng (func (tên chuỗi) ...). – ANisus

+0

Tôi cũng hiểu tại sao bạn có thể đã thay đổi tiêu đề, từ giả định rằng hai hàm có cùng tham số và kiểu kết quả giống hệt nhau. Tuy nhiên, đây không phải là trường hợp khi làm việc với các phương thức kiểu. Sau đó 'func english (...)' và 'Greeting (func english (...))' sẽ khác. Người ta không thể truy cập vào phương pháp loại trong khi người kia có thể. Vì vậy, tôi nghĩ tiêu đề đầu tiên chính xác hơn. – ANisus

+0

Ah, cảm ơn bạn đã cập nhật! Câu trả lời của bạn chắc chắn đã giúp tôi hiểu nó tốt hơn. Tôi bắt đầu thử nó khi tôi chạy vào 'websocket.Handler' là một kiểu hàm với phương thức' ServeHTTP (w http.ResponseWriter, req * http.Request) '(thực hiện giao diện' http.Handler'). Cảm ơn một lần nữa! – ANisus

3

Đang cố gắng để tách các vấn đề ở đây,

type Greeting func(string) string 

func english(name string) string { 
    return return "Hello, " + name 
} 

func main() { 
    var g Greeting 
    g = english 
    fmt.Println(g("ANisus")) 
} 

có phải là cách để khai báo các chức năng tiếng Anh của loại Greeting. Chú ý Lời chào không được sử dụng trong định nghĩa của tiếng Anh, do đó, điều này có thể không đáp ứng yêu cầu của bạn khai báo một chức năng của một loại cụ thể. Nếu không, xin lỗi, không có cách nào trong Go để xác định chức năng của một loại cụ thể (có nghĩa là, được xác định riêng). Có thể tốt hơn nếu bạn nhập một cái gì đó như,

english := Greeting { 
    return return "Hello, " + name 
} 

nhưng không, không có cách nào trong Go. Việc khai báo tiếng Anh không thể sử dụng lời chào, và phải lặp lại chữ ký hàm. Thay vào đó, yêu cầu tiếng Anh thuộc loại Greeting chỉ được thực hiện trong bài tập

g = english 

g được khai báo kiểu Greeting. Nếu tiếng Anh không phải là cùng một loại, dòng sẽ không biên dịch.

Ngoài vấn đề lặp lại chữ ký loại - các vấn đề về phương pháp, ví dụ - không rõ ràng nếu bạn vẫn đang tìm cách khác để tổ chức chức năng của ví dụ của bạn. Nó chắc chắn có thể được thực hiện theo những cách khác. Một ví dụ lớn hơn mặc dù, có thể đặt ra như một câu hỏi riêng biệt, sẽ giúp đỡ.

+1

Tôi đã tìm kiếm những gì bạn minh họa với dòng 'english: = Greeting {...}', nơi bạn đã giải thích rằng có không có cách nào. Nhưng bạn đã làm cho tôi hiểu thêm về cách làm việc với các kiểu hàm theo cách thành ngữ Go. – ANisus

Các vấn đề liên quan