определяющая функция внутри функции - PullRequest
1 голос
/ 22 мая 2019

При определении внутренней функции, которая использует переменные внешней области видимости, я должен передать переменные внутренней функции в качестве параметров?

В моем примере, generate и generate2 оба дают мне один и тот же результат, есть липочему я должен выбрать какой-либо из них?

Код выбирает ключ 1 для генерации комбинаций с ключом 3,4,5, затем выбирает ключ 2 для генерации комбинаций с ключом 3,4,5.

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, playground")

    src := map[int][]string{
        1: []string{"1", "11", "111"},
        2: []string{"2", "22"},
        3: []string{"3"},
        4: []string{"4"},
        5: []string{"5", "55"},
    }

    result2 := generate2(src)

    fmt.Println(result2)

    result := generate(src)

    fmt.Println(result)

}

func generate(src map[int][]string) []string {
    var combo []string
    var add = func(f []string) {
        for _, v := range f {

            for _, p := range src[3] {
                for _, q := range src[4] {
                    for _, r := range src[5] {
                        combo = append(combo, v+p+q+r)
                    }
                }
            }

        }
    }

    add(src[1])
    add(src[2])
    return combo
}

func generate2(src map[int][]string) []string {
    var combo []string
    var add = func(f []string, combo []string, src map[int][]string) []string {
        for _, v := range f {
            for _, p := range src[3] {
                for _, q := range src[4] {
                    for _, r := range src[5] {
                        combo = append(combo, v+p+q+r)
                    }
                }
            }
        }
        return combo
    }

    combo = add(src[1], combo, src)
    combo = add(src[2], combo, src)
    return combo
}

Ответы [ 2 ]

6 голосов
/ 22 мая 2019

При определении внутренней функции, которая использует переменные внешней области видимости, я должен передать переменные внутренней функции как параметры?

Это зависит от того, чего вы хотите достичь.

То, что вы называете «функцией внутри функции», на самом деле называется «замыканием» (а некоторые люди называют это «лямбда»).

Замыкания захватывают переменные из внешней лексической области видимости, на которые есть ссылки в ее теле. В Go этот захват выполняется «по ссылке» или «по имени», что в основном означает, что каждый раз, когда вызывается замыкание, он «видит» current значения переменных, которые он закрывает, а не значения этих переменных в момент создания закрытия - обратите внимание, что программа:

package main

import (
    "fmt"
)

func main() {
    i := 42

    fn := func() {
      fmt.Println(i)
    }

    fn()
    i = 12
    fn()
}

выдаст

42
12

И наоборот, когда вы передаете значения в качестве аргументов для вызовов к замыканию, каждый вызов будет видеть именно те значения, которые ему переданы.

Надеюсь, теперь вы понимаете, что стратегия выбора во многом зависит от того, что вы хотите.

Концептуально вы можете рассматривать замыкание как экземпляр специального анонимного типа данных struct, поля которого являются указателями на переменные, над которыми замыкается замыкание, и каждый вызов этого замыкания аналогичен вызов некоторого (анонимного, единственного) метода, предоставленного этим типом (на самом деле это то, что компилятор обычно делает за вашей спиной, чтобы реализовать замыкание). Такой «метод» может иметь аргументы, и должен ли он иметь их, и что должно идти в поля типа, и какими должны быть аргументы этого метода, можно судить, используя обычный подход, который вы используете с обычными типами.

1 голос
/ 22 мая 2019

В этом контексте между этими двумя функциями нет функциональной разницы. Как вы заметили, локальные функции имеют доступ к локальным переменным без явной их передачи. В вашем примере вы можете предпочесть использовать generate1 для более удобного чтения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...