嵌套函数中使用的变量是否被认为是全局?

发布于 2025-02-03 00:54:12 字数 482 浏览 3 评论 0原文

这是一个愚蠢的问题,所以我很抱歉。这是针对朱莉娅的,但我想这个问题不是语言的特定于语言。

朱莉娅(Julia)有建议,全局变量不应在功能中使用,但是在某些情况下,我不确定变量是全局还是局部。我在函数中定义了一个变量,但对于嵌套函数是全局的。例如,在下面,

a=2;
f(x)=a*x;

变量a被视为全局。但是,如果我们将所有这些包裹在另一个功能中, a 是否仍被视为f的全局?例如,

function g(a)
  f(x)=a*x;
end

我们不使用a作为f的输入,因此它是全局的,但是它仍然仅在g <g <的范围中定义。 /code>,从这个意义上讲,本地也是如此。我不知道。谢谢。

This is a dumb question, so I apologise if so. This is for Julia, but I guess the question is not language specific.

There is advice in Julia that global variables should not be used in functions, but there is a case where I am not sure if a variable is global or local. I have a variable defined in a function, but is global for a nested function. For example, in the following,

a=2;
f(x)=a*x;

variable a is considered global. However, if we were to wrap this all in another function, would a still be considered global for f? For example,

function g(a)
  f(x)=a*x;
end

We don't use a as an input for f, so it's global in that sense, but its still only defined in the scope of g, so is local in that sense. I am not sure. Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

幸福丶如此 2025-02-10 00:54:12

您可以直接检查@dnf所说的确实是这种情况(即变量a在封闭中捕获)。

这是代码:

julia> function g(a)
         f(x)=a*x
       end
g (generic function with 1 method)

julia> v = g(2)
(::var"#f#1"{Int64}) (generic function with 1 method)

julia> dump(v)
f (function of type var"#f#1"{Int64})
  a: Int64 2

在此示例中,您的函数g返回函数。我将v变量绑定到返回的功能,以便能够检查它。

如果您dump绑定到v变量的值,您可以看到a变量存储在闭合中。

封闭中存储的变量不应该为您的代码执行问题一个问题。这是一种典型的模式,例如在某些参数(闭合捕获)中对某些功能进行优化时。

正如您在此代码中看到的那样:

julia> @code_warntype v(10)
MethodInstance for (::var"#f#1"{Int64})(::Int64)
  from (::var"#f#1")(x) in Main at REPL[1]:2
Arguments
  #self#::var"#f#1"{Int64}
  x::Int64
Body::Int64
1 ─ %1 = Core.getfield(#self#, :a)::Int64
│   %2 = (%1 * x)::Int64
└──      return %2

所有内容都是类型稳定的,因此此类代码很快。

尽管在某些情况下会发生拳击(它们应该很少见;它们在您的功能如此复杂以至于编译器无法证明不需要拳击的情况下会发生;如果您将值分配给封闭中捕获的变量):

julia> function foo()
           x::Int = 1
           return bar() = (x = 1; x)
       end
foo (generic function with 1 method)

julia> dump(foo())
bar (function of type var"#bar#6")
  x: Core.Box
    contents: Int64 1

julia> @code_warntype foo()()
MethodInstance for (::var"#bar#1")()
  from (::var"#bar#1")() in Main at REPL[1]:3
Arguments
  #self#::var"#bar#1"
Locals
  x::Union{}
Body::Int64
1 ─ %1  = Core.getfield(#self#, :x)::Core.Box
│   %2  = Base.convert(Main.Int, 1)::Core.Const(1)
│   %3  = Core.typeassert(%2, Main.Int)::Core.Const(1)
│         Core.setfield!(%1, :contents, %3)
│   %5  = Core.getfield(#self#, :x)::Core.Box
│   %6  = Core.isdefined(%5, :contents)::Bool
└──       goto #3 if not %6
2 ─       goto #4
3 ─       Core.NewvarNode(:(x))
└──       x
4 ┄ %11 = Core.getfield(%5, :contents)::Any
│   %12 = Core.typeassert(%11, Main.Int)::Int64
└──       return %12

You can check directly that what @DNF commented indeed is the case (i.e. that the variable a is captured in a closure).

Here is the code:

julia> function g(a)
         f(x)=a*x
       end
g (generic function with 1 method)

julia> v = g(2)
(::var"#f#1"{Int64}) (generic function with 1 method)

julia> dump(v)
f (function of type var"#f#1"{Int64})
  a: Int64 2

In this example your function g returns a function. I bind a v variable to the returned function to be able to inspect it.

If you dump the value bound to the v variable you can see that the a variable is stored in the closure.

A variable stored in a closure should not a problem for performance of your code. This is a typical pattern used e.g. when doing optimization of some function conditional on some parameter (captured in a closure).

As you can see in this code:

julia> @code_warntype v(10)
MethodInstance for (::var"#f#1"{Int64})(::Int64)
  from (::var"#f#1")(x) in Main at REPL[1]:2
Arguments
  #self#::var"#f#1"{Int64}
  x::Int64
Body::Int64
1 ─ %1 = Core.getfield(#self#, :a)::Int64
│   %2 = (%1 * x)::Int64
└──      return %2

everything is type stable so such code is fast.

There are some situations though in which boxing happens (they should be rare; they happen in cases when your function is so complex that the compiler is not able to prove that boxing is not needed; most of the time it happens if you assign value to the variable captured in a closure):

julia> function foo()
           x::Int = 1
           return bar() = (x = 1; x)
       end
foo (generic function with 1 method)

julia> dump(foo())
bar (function of type var"#bar#6")
  x: Core.Box
    contents: Int64 1

julia> @code_warntype foo()()
MethodInstance for (::var"#bar#1")()
  from (::var"#bar#1")() in Main at REPL[1]:3
Arguments
  #self#::var"#bar#1"
Locals
  x::Union{}
Body::Int64
1 ─ %1  = Core.getfield(#self#, :x)::Core.Box
│   %2  = Base.convert(Main.Int, 1)::Core.Const(1)
│   %3  = Core.typeassert(%2, Main.Int)::Core.Const(1)
│         Core.setfield!(%1, :contents, %3)
│   %5  = Core.getfield(#self#, :x)::Core.Box
│   %6  = Core.isdefined(%5, :contents)::Bool
└──       goto #3 if not %6
2 ─       goto #4
3 ─       Core.NewvarNode(:(x))
└──       x
4 ┄ %11 = Core.getfield(%5, :contents)::Any
│   %12 = Core.typeassert(%11, Main.Int)::Int64
└──       return %12
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文