Понимание составного литерала go

Почему присвоение значения функции f не является составным литералом?

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

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

Однако присвоение значения функции функции f в коде выглядит как составное литеральное выражение для типа func () int.

Есть ли причина, по которой объект функции не может быть построен как составной литерал?

package main
import (
    "fmt"
)

func main(){
    var x int = 0

    var f func() int
    f = func() int{ x++; return x * x }  // <---- Why this cannot be a composite literal?

    fmt.Println(f())   // 1
    fmt.Println(f())   // 4
    fmt.Println(f())   // 9

    // Define a type for "func() int" type 
    type SQUARE func() int
    g := SQUARE{ x++; return x * x}   // <--- Error with Invalid composite literal type: SQUARE 

    fmt.Println(g())
}

2 ответа

Делает f = func() int{ x++; return x * x } выглядит как составной литерал?

На самом деле, нет)

Как указано в спецификации:

Составные литералы создают значения для структур, массивов, срезов и карт... Они состоят из типа литерала, за которым следует список элементов, связанный фигурными скобками.

Чтобы сделать это утверждение более ясным, вот производственное правило для составного литерала:

CompositeLit  = LiteralType LiteralValue .

Вы можете видеть, что производственное правило для LiteralValue является:

LiteralValue  = "{" [ ElementList [ "," ] ] "}" .

а также FunctionBody, совсем не выглядит так. По сути, это списокStatements:

FunctionBody = Block .
Block = "{" StatementList "}" .
StatementList = { Statement ";" } .

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

Я не смог найти какой-либо задокументированный ответ на этот вопрос, но самое простое предположение состоит в том, что основные причины:

  • Избежать путаницы. Вот пример, если бы можно было создать составной литерал для функции:
type SquareFunc func() int

type Square struct {
    Function SquareFunc
}

func main() {
    f := SquareFunc{ return 1 }
    s := Square{ buildSquareFunc() }
}

s:= ... строка (которая должна быть составного типа) может быть легко перепутана с первой строкой.

  • Помимо тела, у функции есть еще одна важная вещь - Signature. Если бы вы могли построить составной литерал для функции, как бы вы определяли его аргументы и возвращали имена параметров? Вы можете определить имена в определении типа, но это вызовет негибкость (иногда вы хотите использовать другие имена параметров) и код вроде:
type SquareFunc func(int x) int

func main() {
    x := 1

    f := SquareFunc{ 
        x++
        return x * x
    }
    f(2)
}

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

Вам нужно его отформатировать.

package main

import (
  "fmt"
)

func main(){
   var x int = 0

   var f func() int
   f = (func() int{ x++; return x * x })  // <---- Why this cannot be a composite literal?

   fmt.Println(f())   // 1
   fmt.Println(f())   // 4
   fmt.Println(f())   // 9

   // Define a type for "func() int" type 
   type SQUARE func() int
   g := SQUARE(func()int{ x++; return x * x})   // <--- Error with Invalid composite literal type: SQUARE 

   fmt.Println(g())
}

Оберните вашу переменную f с помощью (). В случаеSQUARE, вам нужно написать func() int перед запуском кода вашей функции

Другие вопросы по тегам