สามารถส่งผ่านฟังก์ชั่นเป็นพารามิเตอร์ได้หรือไม่


158

ใน Java ฉันสามารถทำสิ่งที่ชอบ

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

และ "รัน" รหัสในวิธีการในภายหลัง มันเป็นความเจ็บปวดที่ต้องจัดการ (ชั้นในที่ไม่ระบุชื่อ) แต่สามารถทำได้

Go มีบางอย่างที่ช่วยให้ฟังก์ชัน / การติดต่อกลับถูกส่งผ่านเป็นพารามิเตอร์หรือไม่


7
Nit / clarification สำหรับผู้อ่าน: ใน Java "ฟังก์ชั่น" ไม่สามารถผ่านได้ (ที่จริงแล้ว "ฟังก์ชั่น" ทั้งหมดใน Java เรียกว่าวิธีการที่เหมาะสมกว่า) Runnable (และคลาสภายในที่ไม่ระบุชื่อซึ่งสืบทอดมาจากนั้น) เป็นเพียง: ประเภทที่อ็อบเจกต์ถูกสร้างอินสแตนซ์ที่สมัครรับอินเทอร์เฟซที่ต้องการ ..

2
(หกปีต่อมา ... ) Java ตอนนี้มีวิธีผ่านวิธี (เช่นcontainingObject::instanceMethodName): docs.oracle.com/javase/tutorial/java/javaOO/…
vazor

คำตอบ:


225

ใช่ลองพิจารณาตัวอย่างเหล่านี้:

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 "" })
}

เล่น: http://play.golang.org/p/XNMtrDUDS0

ทัวร์: https://tour.golang.org/moretypes/25 (การปิดฟังก์ชัน)


เป็นไปได้ไหมที่จะส่งผ่านพารามิเตอร์ไปยังฟังก์ชันที่ตัวเองเป็นพารามิเตอร์ด้วย? จากตัวอย่างด้านบนสิ่งที่พิมพ์ออกมานั้นมีรหัสอย่างหนัก: การพิมพ์ 123 การเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นเพื่อให้เราสามารถพิมพ์อย่างอื่นมากกว่า 123 ได้ไหม โดยไม่ต้องประกาศตัวแปรทั่วโลก
Saty

1
หากฉันเข้าใจคำถามของคุณถูกต้องฉันคิดว่าคุณกำลังมองหา func ที่ส่งคืน func ดูที่นี่ที่ฉันแทนที่ฟังก์ชัน "quote123" hardcoded ด้วยฟังก์ชัน "quote" ที่ให้ผลลัพธ์เดียวกันหลังจากที่คุณป้อนข้อมูลplay.golang.org/p/52ahWAI2xsG
dskinner

34

คุณสามารถส่งผ่านฟังก์ชันเป็นพารามิเตอร์ไปยังฟังก์ชันไป นี่คือตัวอย่างของการส่งผ่านฟังก์ชันเป็นพารามิเตอร์ของฟังก์ชัน Go อื่น:

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)
}

คุณสามารถลองใช้งานได้ที่: https://play.golang.org/p/9mAOUWGp0k


2
ขอบคุณ! นี่เป็นตัวอย่างที่ชัดเจนของวิธีใช้ความคิดนี้ให้ดีที่สุด! ฉันสร้างใหม่โดยใช้ตารางการค้นหาของ structs ที่เก็บข้อมูลรวมถึงตัวชี้ไปยังฟังก์ชันที่คุณต้องการใช้งาน สมบูรณ์แบบสำหรับสิ่งนี้!
James O'Toole

15

นี่คือตัวอย่างการใช้งาน "แผนที่" ใน Go หวังว่านี่จะช่วยได้ !!

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

นี่คือตัวอย่างง่ายๆ:

    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
ที่ส่งคืนฟังก์ชันที่ไม่ผ่านฟังก์ชัน
John LaBarge

2

ฉันหวังว่าตัวอย่างด้านล่างจะให้ความชัดเจนมากขึ้น

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

ใช่ไปยอมรับฟังก์ชั่นชั้นหนึ่ง

ดูบทความ"ฟังก์ชั่นชั้นหนึ่งใน Go"สำหรับลิงค์ที่มีประโยชน์


4
โปรดขยายการตอบกลับนี้บ้าง รวมถึงตัวอย่างลิงก์ไปยังการอ้างอิง (เช่นการอ้างอิงจริง) ฯลฯ

3
จริงๆแล้วมี 0 ข้อมูลในหน้านั้นเพียงเชื่อมโยงไปยังตัวอย่างโง่โดยรหัสที่มา
OZ_
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.