Зачем использовать оператор внутри оператора «if»?

#if-statement #go

#if-statement #Вперед

Вопрос:

В Go tour показан пример, в котором у них есть дополнительный оператор в той же строке, что и оператор «if», и они объясняют это следующим образом: the if statement can start with a short statement to execute before the condition.

 func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    }
    return lim
}
  

Я не вижу необходимости в этом синтаксисе и нахожу его очень запутанным. Почему бы просто не написать v := math.Pow(x, n) в предыдущей строке?

Причина, по которой я спрашиваю, заключается в том, что, как я выяснил, синтаксис находит свой путь в язык Go после тщательного рассмотрения, и, похоже, там нет ничего из прихоти.

Я предполагаю, что мой актуальный вопрос будет: какую конкретную проблему они пытаются решить, используя этот синтаксис? Что вы получаете, используя его, чего у вас не было раньше?

Комментарии:

1. Область действия? Все v еще находится в области видимости после закрывающей фигурной скобки } и до return lim ? Я ожидаю, что нет, и именно поэтому он написан таким образом.

Ответ №1:

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

  • правильное определение области: дайте переменной только ту область, которую она должна иметь
  • правильная семантика: дайте понять, что переменная принадлежит только определенной условной части кода

Несколько примеров, которые я помню с головы до ног:

Ограниченные области:

 if v := computeStuff(); v == expectedResult {
    return v
} else {
    // v is valid here as well
}

// carry on without bothering about v
  

Проверка ошибок:

 if perr, ok := err.(*os.PathError); ok {
    // handle path error specifically
}
  

или, в более общем смысле, проверка типов:

 if someStruct, ok := someInterface.(*SomeStruct); ok {
    // someInterface is actually a *SomeStruct.
}
  

Проверка ключа в картах:

 if _, ok := myMap[someKey]; ok {
    // key exists
}
  

Комментарии:

1. Это утверждение типа с ok флагом круто! Не видел многого из этого.

2. @SimonWhitehead Жаль, потому что вы всегда должны проверять утверждения типа 🙂

3. Конечно, я не очень долго играл с Go, поэтому мое знакомство с ним, написанным другими людьми, довольно ограничено 🙂 Это может объяснить нескольким здешним завсегдатаям, почему я оставляю такие восторженные комментарии! : D

4. Вероятно, также потому, что они поняли, что конструкция C of if (s = getChar()) очень полезна, но также является своего рода злой и плохо работает с несколькими возвращаемыми значениями.

Ответ №2:

Поскольку ваши переменные содержатся в области видимости, обратите внимание, что они v объявлены в другой области видимости.

Более прямой пример для понимания областей применения: http://play.golang.org/p/fInnIkG5EH

 package main

import (
    "fmt"
)

func main() {
    var hello = "Hello"

    {
        hello := "This is another one"
        fmt.Println(hello)
    }

    if hello := "New Hello"; hello != ""{
       fmt.Println(hello)
    }

    fmt.Println(hello)
}