Các chức năng có thể được thông qua như là tham số?


157

Trong Java tôi có thể làm một cái gì đó như

derp(new Runnable { public void run () { /* run this sometime later */ } })

và "chạy" mã trong phương thức sau. Đó là một nỗi đau để xử lý (lớp bên trong vô danh), nhưng nó có thể được thực hiện.

Liệu Go có một cái gì đó có thể tạo điều kiện cho một chức năng / gọi lại được truyền vào như một tham số không?


7
Nit / làm rõ cho người đọc: Trong Java, "các hàm" không thể vượt qua (thực ra, tất cả các "hàm" trong Java đều được gọi là Phương thức một cách thông minh hơn). Runnable (và các lớp bên trong ẩn danh xuất phát từ đó) chỉ là: một loại mà các đối tượng được khởi tạo đã đăng ký vào giao diện bắt buộc ..

2
(Sáu năm sau ...) Java hiện có một cách để vượt qua các phương thức (ví dụ containingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/ Lỗi
vazor 6/12/18

Câu trả lời:


224

Vâng, hãy xem xét một số ví dụ sau:

package main

import "fmt"

// convert types take an int and return a string value.
type convert func(int) string

// value implements convert, returning x as string.
func value(x int) string {
    return fmt.Sprintf("%v", x)
}

// quote123 passes 123 to convert func and returns quoted string.
func quote123(fn convert) string {
    return fmt.Sprintf("%q", fn(123))
}

func main() {
    var result string

    result = value(123)
    fmt.Println(result)
    // Output: 123

    result = quote123(value)
    fmt.Println(result)
    // Output: "123"

    result = quote123(func(x int) string { return fmt.Sprintf("%b", x) })
    fmt.Println(result)
    // Output: "1111011"

    foo := func(x int) string { return "foo" }
    result = quote123(foo)
    fmt.Println(result)
    // Output: "foo"

    _ = convert(foo) // confirm foo satisfies convert at runtime

    // fails due to argument type
    // _ = convert(func(x float64) string { return "" })
}

Chơi: http://play.golang.org/p/XNMtrDUDS0

Tham quan: https://tour.golang.org/moretypes/25 (Đóng cửa chức năng)


Có thể truyền tham số cho hàm mà chính nó cũng là tham số không? Trong các ví dụ trên, những thứ được in được mã hóa cứng: In 123. Có thể thực hiện bất kỳ thay đổi nào để chúng tôi có thể in một cái gì đó khác hơn 123 không? Mà không khai báo biến toàn cục.
Saty

1
Nếu tôi hiểu chính xác câu hỏi của bạn, tôi nghĩ rằng bạn đang tìm kiếm một func trả về một func, hãy xem ở đây nơi tôi thay thế một hàm "quote123" được mã hóa cứng bằng một hàm "quote" đạt được kết quả tương tự sau khi bạn chuyển một số đầu vào: play.golang.org/p/52ahWAI2xsG
dskinner

34

Bạn có thể truyền hàm dưới dạng tham số cho hàm Go. Dưới đây là một ví dụ về việc truyền hàm dưới dạng tham số cho hàm Go khác:

package main

import "fmt"

type fn func(int) 

func myfn1(i int) {
    fmt.Printf("\ni is %v", i)
}
func myfn2(i int) {
    fmt.Printf("\ni is %v", i)
}
func test(f fn, val int) {
    f(val)
}
func main() {
    test(myfn1, 123)
    test(myfn2, 321)
}

Bạn có thể dùng thử tại: https://play.golang.org/p/9mAOUWGp0k


1
Cảm ơn bạn! Đây là một ví dụ thực sự rõ ràng về cách sử dụng tốt nhất ý tưởng này! Tôi đã tạo lại nó bằng cách sử dụng bảng tra cứu các cấu trúc lưu trữ thông tin, bao gồm một con trỏ tới hàm bạn muốn thực thi. Hoàn hảo cho việc này!
James O'Toole

14

Dưới đây là mẫu triển khai "Bản đồ" trong Go. Hi vọng điêu nay co ich!!

func square(num int) int {
    return num * num
}

func mapper(f func(int) int, alist []int) []int {
    var a = make([]int, len(alist), len(alist))
    for index, val := range alist {

        a[index] = f(val)
    }
    return a
}

func main() {
    alist := []int{4, 5, 6, 7}
    result := mapper(square, alist)
    fmt.Println(result)

}

8

Đây là một ví dụ đơn giản:

    package main

    import "fmt"

    func plusTwo() (func(v int) (int)) {
        return func(v int) (int) {
            return v+2
        }
    }

    func plusX(x int) (func(v int) (int)) {
       return func(v int) (int) {
           return v+x
       }
    }

    func main() {
        p := plusTwo()
        fmt.Printf("3+2: %d\n", p(3))

        px := plusX(3)
        fmt.Printf("3+3: %d\n", px(3))
    }

4
đó là trả về một chức năng không vượt qua một chức năng
John LaBarge

2

Tôi hy vọng ví dụ dưới đây sẽ cung cấp rõ ràng hơn.

package main

type EmployeeManager struct{
    category            string
    city                string
    calculateSalary     func() int64
}


func NewEmployeeManager() (*EmployeeManager,error){

    return &EmployeeManager{
        category : "MANAGEMENT",
        city : "NY",
        calculateSalary: func() int64 {
            var calculatedSalary int64
            // some formula
            return calculatedSalary
        },
    },nil
}

func (self *EmployeeManager) emWithSalaryCalculation(){
    self.calculateSalary = func() int64 {
        var calculatedSalary int64
        // some new formula
        return calculatedSalary
    }
}

func updateEmployeeInfo(em EmployeeManager){
    // Some code
}

func processEmployee(){
    updateEmployeeInfo(struct {
        category        string
        city            string
        calculateSalary func() int64
    }{category: "", city: "", calculateSalary: func() int64 {
        var calculatedSalary int64
        // some new formula
        return calculatedSalary
    }})
}

-2

Có Go không chấp nhận các chức năng hạng nhất.

Xem bài viết "Chức năng hạng nhất trong Go" để biết các liên kết hữu ích.


4
Hãy mở rộng về phản ứng này một số; bao gồm một ví dụ, liên kết đến tham chiếu (ví dụ: tham chiếu thực tế), v.v.

3
thực tế có 0 thông tin trên trang đó, chỉ liên kết đến ví dụ ngu ngốc bằng mã nguồn.
OZ_
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.