Закрытие Фибоначчи

Я слежу за гастролями на своем официальном сайте, и меня попросили написать генератор Фибоначчи. Вот он:

 package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    first := 0
    second := 0
    return func() int{
        if(first == 0) {
         first = 1
         second = 1
         return 0
        }else {
            current := first   
            firstc := second
            second = first + second
            first = firstc
            return current
        }



    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Это работает. Однако я считаю это очень уродливым, и я уверен, что должно быть лучшее решение. Я думал о публикации этого в обзоре кода, так как я прошу лучшего подхода, я думал, что это подходящее место для публикации.

Есть ли лучший способ написать этот код?

Вот задача:

Реализуйте функцию фибоначчи, которая возвращает функцию (замыкание), которая возвращает последовательные числа фибоначчи.

Ответ 1

Мой любимый чистый способ реализовать итерацию по номерам Фибоначчи - это использовать first как f я - 1 и second как f i. Уравнение Фибоначчи утверждает, что:

f я + 1= f i + f я - 1

За исключением случаев, когда мы пишем это в коде, в следующем раунде мы увеличиваем i. Итак, мы эффективно делаем:

f next i= f current i + f current я - 1

и

f next я - 1= f current я - 1

Как мне это реализовать в коде:

first, second = second, first + second

Часть first = second соответствует обновлению f next я - 1= f current я - 1, а часть second = first + second соответствует обновлению f next i= f current i + f current я - 1.

Тогда все, что нам осталось сделать, это вернуть прежнее значение first, поэтому мы сохраним его в переменной temp, прежде чем делать обновление. В итоге получаем:

// fibonacci returns a function that returns
// successive fibonacci numbers from each
// successive call
func fibonacci() func() int {
    first, second := 0, 1
    return func() int {
        ret := first
        first, second = second, first+second
        return ret
    }
}

Посмотрите в действии на Go Playground.

Ответ 2

Я бы использовал множественное назначение, уменьшал длину идентификаторов и удалял это, если statment:

func fibonacci() func() int {
    var a, b int
    b = 1
    return func() int {
        ret := a
        a, b = b, a+b
        return ret
    }
}

Ответ 4

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    a, b, sum := 1, 1, 0
    return func() int {
        a,b = b,sum
        sum = a + b
        return b
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Ответ 5

Помимо уже предоставленных ответов вы также можете использовать для этого функцию отсрочки:

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    secondLast := 0
    last := 1
    return func() int {
        defer func() {
            secondLast, last = last, secondLast+last
        }()
        return secondLast
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Go Playground

Но я думаю, что ответы от jwoodalls - самые эффективные.

Редактировать: Но если вы хотите использовать целые числа без знака (чтобы показать, сколько чисел Фибоначчи вы можете вычислить в вашей архитектуре;)), вам придется использовать либо подход с переменной, содержащей возвращаемое значение, либо функцию отсрочки.

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an uint.
func fibonacci() func() uint {
    var secondLast uint
    var last uint = 1
    return func() uint {
        defer func() {
            secondLast, last = last, secondLast + last
        }()
        return secondLast
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Go Playground

EditEdit: Или еще лучше: используйте float64 !!!

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an float64.
func fibonacci() func() float64 {
    var secondLast float64
    var last float64 = 1
    return func() float64 {
        defer func() {
            secondLast, last = last, secondLast+last
        }()
        return secondLast
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Go Playground

Ответ 6

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

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    f1 := 0
    f2 := 1
    return func() int {
        temp := f1+f2
        temp2 := f1
        f1 = f2
        f2 = temp
        return temp2
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}

Ответ 7

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
    first:=0
    second:=0
    return func() int{
        if second == 0 {
            second = 1
        } else if first == 0 {
            first = 1
        } else {
            first, second = second, first + second
        }
        return second
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        fmt.Println(f())
    }
}