Понимание go составной литерал - PullRequest
0 голосов
/ 26 апреля 2020

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

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

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

Однако значение функции присваивание f в коде выглядит как составное литеральное выражение для типа fun c () 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 ]

3 голосов
/ 26 апреля 2020

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

Не совсем)

Как spe c состояния :

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

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

CompositeLit  = LiteralType LiteralValue .

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

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

и FunctionBody , совсем не похоже на это. По сути, это список Statement:

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:= ... строка (которая должна быть составного типа) могла бы быть легко перепутана с 1-й строкой.

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

func main() {
    x := 1

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

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

0 голосов
/ 26 апреля 2020

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

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 перед запуском кода вашей функции

...