golang:隐式vs显式func定义

时间:2017-03-24 15:04:17

标签: go

考虑这个包:

package A
var X="change me"
var Y=func(i int) int { return i*i) }
func Z(i int) int { return -i) }

两个显式变量(X,Y)可以在另一个包中更改,比如main ...

package main
import "A"
func main () {
    A.X="done"
    A.Y=func (i int) int { return i*i*i }
    print(A.X,A.Y(7))
    //... but A.Z apparently can't be changed.
    //A.Z=func (int i) int { return i*i*i } //main.go:8: cannot assign to A.Z
}

显然,定义func变量(如Y)和显式func(如Z)之间存在差异。我用Google搜索了这一点,但在启蒙的方式中找不到多少。似乎var SomeFunc = func(...)确实定义了一个变量,但是func SomeFunc(...)定义了一个常量。

PS:我在研究这个时发现的一个小礼物,我在Go书中没有看到过,我到目前为止已经阅读过了。包导入之前的一个点导入名称,而不必对它们进行限定:

package main
import . "A"
func main () {
    X="done"
    Y=func (i int) int { return i*i*i }
    print(X,Y(7))
}

2 个答案:

答案 0 :(得分:3)

func SomeFunc()实质上创建了标识符SomeFunc与您定义的函数的强/常量/不可变绑定。当你创建一个这样的变量时:

var (
    SomeFunc = func(i int) int {
        return i * 2
    }
)

您创建了func(int) int类型的全局变量。您可以稍后重新分配此变量。对于func SomeFunc标识符,您无法真正做到这一点。简单地说,这是因为func SomeFunc()将函数直接绑定到标识符。 var SomeFunc方法创建一个变量(在这种情况下为func(int) int),并使用您指定的函数初始化该变量。与变量的情况一样:可以重新分配。

Example

可以对函数做什么,是使用范围变量来遮蔽它们。这可能会被大多数短语所标记,但这是一种技术/技巧,有时可用于测试

Example

至于dot-imports:请不要这样做,除非有非常非常非常的理由。一个很好的理由是你编写一个添加的包到现有的包中,所以你不再导入现有的包,而是导入你自己的包。可以将其视为扩展包。 99%的时间。不管怎样,在导入encoding/json以将json序列化注释添加到结构时,不要使用它来解决错误。在这些情况下,请使用下划线:

package foo
import (
    "encoding/json"
)

type Bar struct {
    Foobar string `json:"foobar"`
}

func New() *Bar {
    &Bar{"Default foobar"}
}

不知道golang 1.8,但是这样的包可能导致编译器错误(包编码/ json导入但未使用)。要消除该错误,您只需将导入更改为:

import(
    _ "encoding/json"
)

点包,下划线和包别名都遵循相同的规则:尽可能少地使用它们。

示例中使用的代码:

package main

import (
    "fmt"
)

var (
    SomeFunc = func(i int) int {
        return i * 2
    }
)

func main() {
    fmt.Println(SomeFunc(2)) // output 4
    reassign()
    fmt.Println(SomeFunc(2)) // output 8
    shadowReassign()
    fmt.Println(SomeFunc(2)) // output 2
}

// global function
func reassign() {
    // assign new function to the global var. Function types MUST match
    SomeFunc = func(i int) int {
        return i * 4
    }
}

// assign function to local reassign variable
func shadowReassign() {
    reassign := func() {
        // same as global reassign
        SomeFunc = func(i int) int {
            return i
        }
    }
    reassign()
}

答案 1 :(得分:0)

声明使用函数值初始化的变量之间存在差异:

local fence = require("lib.fence")
local physics = require("physics")
local t = {}
    local stages = {yellow = 1, lila = 1, red = 1}
    local sizes = {1, 3.625, 7.25}
    t.colors = {"yellow", "lila", "red"}
    t.growing = false

    t.setSize = function(fill)
        local tHeight = fill.contentHeight * sizes[stages[fill.col]]
        local tScale = tHeight / fill.contentHeight
        fill.yScale = tScale

    end

    t.grow = function(group, color, hero)
        local counter = 0
        stages[color] = stages[color] + 1
        for i = 1, group.numChildren, 1 do
            if group[i].col == color then
                counter = counter + 1
                local function newPhysics() t.physics(group) end
                if counter == 1 then
                    local function reset() t.growing = false if stages[color] == 3 then stages[color] = 1; newPhysics(); end end
                    local function start() t.growing = true end
                    transition.to(group[i], {time = 260, yScale = sizes[stages[color]], onStart = start, onComplete = reset})
                else
                    transition.to(group[i], {time = 250, yScale = sizes[stages[color]], onStart = start})
                end
            end
        end
    end

    t.physics = function(target)
        if target.numChildren == nil then
            physics.removeBody(target)
            local function add()
                physics.addBody( target, "static", {isSensor = true} )
                target.collision = function(self, event)
                    if event.phase == "began" then
                        target.count = target.count + 1
                        if target.count == 1 then
                            t.grow(target.parent, self.col, event.other)
                        end
                    elseif event.phase == "ended" then
                        target.count = 0
                    end
                end
            end
            timer.performWithDelay(1, add, 1)
        else
            for i = 1, target.numChildren, 1 do
                physics.removeBody( target[i] )
                physics.addBody( target[i], "static", {isSensor = true} )
                target[i].name = "fill"
                local fill = target[i]
                fill.count = 0
                fill.collision = function(self, event)
                    if event.phase == "began" then
                        self.count = self.count + 1
                        if self.count == 1 and event.other.x ~= nil then
                            t.grow(target, self.col, event.other)
                        end
                    else
                        fill.count = 0
                    end
                end
                fill:addEventListener("collision")
            end
        end
    end

    t.setColor = function(fill)
        local colors = {
            {238 / 255, 228 / 255, 28 / 255},
            {38 / 255, 33 / 255, 77 / 255},
            {175 / 255, 24 / 255, 52 / 255},
        }
        local names = {"yellow", "lila", "red"}
        local r = math.random(3)
        fill.fill = colors[r]
        fill.col = names[r]
    end

    t.create = function(fences, group, colors)
        local fills = {}
        for i = 1, #fences, 1 do
            local rCol = math.random(3)
            local col
            if rCol == 1 then
                col = colors.yellow
            elseif rCol == 2 then
                col = colors.lila
            else
                col = colors.red
            end
            fills[i] = display.newRect(
                group, fences[i].x + fences[i].contentWidth * 0.125, fences[i].y,
                fences[i].contentWidth * 0.9, (fences[i].contentHeight * 0.5 / 3)
            )
            fills[i].dPosX = fills[i].x
            fills[i].y = display.contentHeight- fills[i].contentHeight / 2
            fills[i].fill = col
            fills[i].col = t.colors[rCol]
            fills[i].increased = false
        end
        return fills
    end

    t.move = function(fills, fences, group)
        for i = 1, #fills, 1 do
            local fill = fills[i]
            function fill:enterFrame()
                self:translate(fence.speed, 0)
                if t.growing == false then
                    t.setSize(self)
                end
                if self.x > display.contentWidth + 0.55 * fences[i].contentWidth then
                    local xT = {}
                    for i = 1, group.numChildren, 1 do
                        xT[i] = group[i].x
                    end
                    local function compare(a, b) return a < b end
                    table.sort(xT, compare)
                    self.x = xT[1] - fences[i].contentWidth * 0.98
                    t.setColor(self)
                    local function newPhysics() t.physics(self) end
                    timer.performWithDelay( 25, newPhysics, 1 )
                    self:toBack()
                end
            end
            Runtime:addEventListener("enterFrame", fill)
        end
    end
return t

并声明一个函数:

var Y=func(i int) int { return i*i) }

specification says this about declarations

  

声明将非空标识符绑定到常量,类型,变量,函数,标签或包。

specification also says

  

函数声明将标识符(函数名称)绑定到函数。

func Z(i int) int { return -i) } 的声明将变量绑定到名称。使用函数值初始化此变量。 Y的声明将函数绑定到名称。

  

如果出现显式句点(。)而不是名称,则在该包的包块中声明的所有包的导出标识符将在导入源文件的文件块中声明,并且必须在没有限定符的情况下访问。