精华内容
下载资源
问答
  • 默认情况下,如果声明函数的时候,参数的不指明是变量还是常量,则默认是常量的。如果要在函数中做相应改变参数的操作,则需要在声明参数的类型。 传入函数的参数的数值不变,说明传入函数的参数,传的是一个数值的...

    默认情况下,如果声明函数的时候,参数的不指明是变量还是常量,则默认是常量的。如果要在函数中做相应改变参数的操作,则需要在声明参数的类型。如下:

    //将一个十进制转换为二进制
    func toBinary(var number:Int)->String{
        var result : String = ""
        while number != 0 {
            result = String(number%2) + result
            number /= 2
        }
        return result
    }
    var number = 10
    toBinary(number)//"1010"
    number//10

    此时,传入函数的参数的数值不变,说明传入函数的参数,传的是一个数值的副本,而不是传引用。进过运算后,不会改变原有的参数的大小,而是改变该参数的副本的大小。而在Swift语言中,不管是传的是int string 还是数组,字典,元组,都是传数值,不是传引用。

    如果确实需要使得调用前的数值发生变化,则需要用到inout

    func swapTwoInts(inout a :Int,inout b:Int){
        let t = a
        a = b
        b = t
    }
    var x = 0,y = 100
    x//0
    y//100
    
    swapTwoInts(&x, &y)
    x//100
    y//0
    展开全文
  • 文章目录IDEA - 【抽取变量常量】快速抽取(方法,变量,字段,常量参数等),重构,优化代码1、抽取变量2、示例3、抽取成常量 IDEA - 【抽取变量常量】快速抽取(方法,变量,字段,常量参数等),重构,...

    IDEA - 【抽取变量,常量】快速抽取(方法,变量,字段,常量,参数等),重构,优化代码


    1、抽取变量

    选中代码

    在这里插入图片描述

    通过选择一个变量值,然后右键菜单
    在这里插入图片描述

    或者通过菜单栏
    在这里插入图片描述

    2、示例

    选择你是需要抽取一个还是所有的
    在这里插入图片描述

    抽取完成

    在这里插入图片描述

    3、抽取成常量

    你认为他是一个不变的值?是一个常量?抽取成常量即可
    在这里插入图片描述

    抽取完成

    在这里插入图片描述
    但是这里他没有说让你选择几个,而是默认只弄了你选中的那个,不是特别智能

    第二次抽取时,会多出来一个常量,而不是复用

    在这里插入图片描述

    展开全文
  • 写在之前函数的参数,我在之前的文章中也提到过,参数这个东西我感觉还是比较有话题的,你可能在某些地方听说过诸如「形参」,「实参」 and so on...那么这些到底什么呢?下面我们就来详细的说一下函数的参数和...

    写在之前

    函数的参数,我在之前的文章中也提到过,参数这个东西我感觉还是比较有话题的,你可能在某些地方听说过诸如「形参」,「实参」 and so on...那么这些到底是什么呢?下面我们就来详细的说一下函数的参数和变量的问题。

    参数 & 变量

    我们用 def 来定义函数,函数名后面的括号里如果有变量的话,它们通常被成为「形参」;在我们调用的时候,给函数提供的值我们称它为「实参」,或者叫「参数」也是 ok 的。其实我觉得我们完全可以简化一下,可以笼统的把函数括号里的变量叫做「参数」,当然叫做「变量」也是可以的,只要你知道指的是什么就好了。

    如果非要有人较真,就是要区分参数和变量,我在这里引用一段网上看到的 “微软网站上关于此问题的说明”,你可以尝试看一下,标题叫 -- 参数和变量的差异(Visual Basic),下面的图片是我从官网上的截图:

    如果你真的硬着头皮看完了上述的内容,你就会发现里面的一些关键词:参数,变量,形参,实参,本来我们只是想弄懂参数和变量的的区别,结果又冒出两个别的词,其实根本不需要担心,在学习编程的时候,类似的东西有很多名词,你现在听过了,下次有人说起的时候你就不用担心了。

    其实在 Python 中,并没有搞得这么复杂,如果你看完上面截图的内容,再来看下面的代码,你就会发现很多事情其实是很明朗的:

    >>> def add(x): # x 是形参

    ... y = 10 # y 是变量

    ... return x + y # 这里的 x 就是形参作为变量来用

    ...

    >>> x = 20 # x 是变量

    >>> add(x) # x 是参数,但它是由上面那行的变量 x 传递对象 20 的引用

    30

    你看,是不是没有那么复杂,所以名字是什么不是最关键的,最重要的是你要明白在函数名后面的括号里的东西的作用是 “传递对象的引用”。

    我们再来看一个例子:

    >>> def add_digit(my_list):

    ... my_list.append(9999)

    ... return my_list

    ...

    >>> x = [1,2,3]

    >>> y = add_digit(x)

    >>> y

    [1, 2, 3, 9999]

    >>> x

    [1, 2, 3, 9999]

    >>> id(y)

    38793288L

    >>> id(x)

    38793288L

    我在写列表的时候说过列表是可以被原地修改的,加上上面我们说过的参数的特点,上面的操作其实就不难理解了。

    原本列表 x 是在函数外面的,既可以理解成 x 和 函数是属于「同级」的,只不过是分属于两个不同的个体,按照我们的常规理解,同级的个体,如果一个个体的内部发生了变化,对于另一个个体来说是没法影响的(注意我说的「同级」,「个体」),但是事实是改变了,因为参数是 「传递对象的引用」,所以函数个体内部的小变动影响到了 x 个体,颇有 “以下犯上” 的意思。

    花这么长的篇幅写这些的原因,终归还是希望你能很深的记住这点:「函数的参数传递对象的引用」,重要的事刚好说了三遍。

    展开全文
  • 第 3 章 变量常量

    2021-01-26 18:24:10
    第 3 章 变量常量 Julia 一种可选类型化的编程语言。Julia 代码中的任何值都有类型的。而一个区别在于,一个值的类型由我们显式指定的,还是由 Julia 在自行推断之后附加上的。例如: julia> typeof(2020...

    第 3 章 变量与常量

    Julia 是一种可选类型化的编程语言。Julia 代码中的任何值都是有类型的。而一个区别在于,一个值的类型是由我们显式指定的,还是由 Julia 在自行推断之后附加上的。例如:

    julia> typeof(2020)
    Int64
    
    julia> 
    

    我调用了一个名为typeof的函数,并把2020作为参数值传给了它。2020本身是一个代表了整数值的字面量(literal)。虽然我没有明确指定这个值是什么类型的,但是 Julia 却可以推断出来。经过推断,Julia 认为它的类型是Int64——一个宽度为 64 个比特(bit)的有符号的整数类型。Int64本身是一个代表了类型的标识符,也可以称之为类型字面量。在一个 64 位的计算机系统当中,Julia 程序中的整数值的默认类型就是Int64。如果你使用的是 32 位的计算机系统,那么这里回显的内容就应该是Int32

    我们在做运算的时候,不太可能只使用值本身去参与运算。因为总有一些中间结果需要被保存下来。就算我们使用计算器去做一些稍微复杂一点的算术运算,肯定也是如此。对于计算机系统而言,那些中间结果可以被暂存到某个内存地址上。当需要它的时候,我们再去这个地址上去取。

    内存地址记忆起来会比较困难。所以,一个更好的方式是,使用一个代号(或者说标识符)去代表某个中间结果。或者说,把一个标识符与一个值绑定在一起,当我们输入这个标识符的时候就相当于输入了这个值。这种可变的绑定关系就被称为变量。这个标识符就被称为变量名。

    图 3-1 标识符与值
    图 3-1 标识符与值

    3.1 变量的定义

    变量不只能代表所谓的中间结果,而是可以代表任何值。当我们在 REPL 环境中定义一个变量的时候,它就会回显该变量名所代表的值。例如:

    julia> x = 2020
    2020
    
    julia> 
    

    在这之后,我们也可以输入这个变量名,以此让 REPL 环境回显它代表的那个值:

    julia> x
    2020
    
    julia> 
    

    然而,当我们输入y这个标识符的时候,会发现它无法回显某个值:

    julia> y
    ERROR: UndefVarError: y not defined
    
    julia> 
    

    这是因为y还没有被定义,Julia 并不知道它代表了什么。那什么是定义呢?更确切地说,什么是变量的定义呢?我们在前面说过,变量相当于一个标识符与值的绑定。那么,对这种绑定的描述就是变量的定义。在 Julia 中,变量的定义一般由标识符、赋值符号=和值字面量构成。就像我们在前面展示的那样。

    3.2 变量的命名

    3.2.1 一般规则

    Julia 变量的名称是大小写敏感的。也就是说,yY并不是同一个标识符,它们可以代表不同的值。

    变量名必须以大写的英文字母A-Z、小写的英文字母a-z、下划线_,或者代码点大于00A0的 Unicode 字符开头。代表数字的字符不能作为变量名的首字符,但是可以被包含在名称的后续部分中。当然,变量名中肯定不能夹杂空格符,以及像制表符、换行符这样的不可打印字符。

    总之,大部分 Unicode 字符都可以作为变量名的一部分。即使你不知道什么是 Unicode 编码标准也没有关系。我们会在后面讨论字符和字符串的时候介绍它。

    由此,Julia 允许我们把数学符号当做变量名,例如:

    julia> δ = 3
    3
    
    julia> 
    

    你可能会问:怎么才能输入δ?这又涉及到了 LaTeX 符号。简单来说,LaTeX 是一个排版系统,常被用来排版学术论文。因为这种论文中经常会出现复杂表格和数学公式,所以 LaTeX 自有一套方法去表现它们。我们没必要现在就去专门学习 LaTeX。你只要知道,如果需要输入数学符号的话,那么就可以利用 LaTeX 符号。

    具体的做法是,先输入某个 LaTeX 符号(比如\delta)再敲击 Tab 键,随后对应的数学符号(比如δ)就可以显示出来了。如果你不知道一个数学符号对应的 LaTeX 符号是什么,那么可以在 REPL 环境的 help 模式下把那个数学符号复制、黏贴到提示符的后面,然后回车。比如这样:

    help?> δ
    "δ" can be typed by \delta<tab>
    
    search: δ
    
      No documentation found.
    
      δ is of type Int64.
    
      Summary
      ≡≡≡≡≡≡≡≡≡
    
      primitive type Int64 <: Signed
    
      Supertype Hierarchy
      ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
    
      Int64 <: Signed <: Integer <: Real <: Number <: Any
    
    julia> 
    

    3.2.2 变量名与关键字

    虽然变量命名的自由度很大,但还是有一些约束的。其中最重要的是,你不能使用 Julia 已有的单一的关键字作为变量名。更广泛地说,所有程序定义的名称都不能与任何一个单一的关键字等同。Julia 中单一的关键字目前一共有 29 个。我把它们分成了 7 个类别:

    • 表示值的关键字:falsetrue
    • 定义程序定义的关键字:constgloballocalfunctionmacrostruct
    • 定义(无名)代码块的关键字:begindoendletquote
    • 定义模块的关键字:baremodulemodule
    • 引入或导出的关键字:importusingexport
    • 控制流程的关键字:breakcontinueelseelseifforifreturnwhile
    • 处理错误的关键字:catchfinallytry

    其中,程序定义指的是变量、常量、类型、有名函数、宏或者结构体。所有的程序定义都是有名称的,或者说可以由某个标识符指代。其中的有名函数和宏也可以被称为有名的代码块。

    所谓的无名代码块,与有名的代码块一样也是有明显边界的一段代码,但是并没有一个标识符可以指代它们。注意,我把关键字end划分为了定义(无名)代码块的关键字。但实际上,我们在定义有名函数、宏、结构体和模块的时候也需要用到它。

    另外,模块也是一个有名的代码块。并且,一个 Julia 程序的主模块(即入口程序所属的那个模块)就是它的最外层代码块。在 Julia 中,并没有一个可以囊括所有代码的全局代码块。这与很多主流的编程语言都是不同的。我们可以说,Julia 程序就是由一些具有依赖关系的模块组成的。换句话讲,Julia 程序中的代码要么在主模块中,要么在主模块依赖的那些模块中。不用着急,我会在后面专门用一章来讲解模块。

    关于以上这些关键字的用法,我们在后面也都会讲到。所以你现在只要知道它们不能被作为变量名就可以了。

    3.2.3 变量名与作用域

    我们在前面说过,Int64是一个代表了类型的标识符。又因为这个标识符的作用域相当于是全局的,所以我们设定的变量名就不能与它重复。更宽泛地讲,我们的变量名肯定不能与任何一个 Julia 预定义的类型的名称相同。

    什么叫作用域呢?其含义是,标识符可以被其他代码直接引用的一个区域。一旦超出这个区域,这个标识符在默认情况下就是不可见的。比如,我们在第 1 章定义过一个叫做MyArgs的模块,并且其中有一个名叫get_parameter的函数。当时的情况是,我们无法在这个模块之外直接使用这个函数的本名来引用它。如果你翻回去看的话,就能见到我们的引用方式是MyArgs.get_parameter。这被称为(针对这个get_parameter函数的)限定名。

    严格来讲,Julia 中没有任何一个标识符的作用域真正是全局的。但是,由于我们定义的所有模块都隐含了Core模块,所以在该模块中直接定义的那些标识符的作用域就相当于是全局的。Int64以及其他代表了某个类型的标识符都在其中。因此,我们设定的变量名肯定不能与Core模块中那些基本的程序定义重名。

    关于作用域,还有一些内容是我们必须要知道的。Julia 中的很多代码块都会自成一个作用域,比如模块就是这样。但由于这会涉及到一些我们还未曾讲到的重要知识,所以我把它们放到了流程控制的那一部分。那里会有关于变量作用域的更多内容。

    3.3 变量的类型

    我们都知道,一个变量的值是可变的。但你可能不知道的是,在 Julia 中,变量的类型也是可以改变的。更确切地说,我们可以为同一个变量先后赋予不同类型的值。Julia 的变量实际上是没有类型的,只有值才有类型。但为了描述方便,我们仍然会说“变量的类型”。你要记住,它真正的意思是“变量中的值的类型”。下面举一个例子:

    julia> y = 2020
    2050
    
    julia> y = "2050"
    "2050"
    
    julia> 
    

    虽然我们还没有专门讲类型,但在这里可以先形成一个简单的认知。在上例中,我先把一个Int64类型的值2020赋给了变量y。紧接着,我又把一个String类型(也就是字符串类型)的值"2050"赋给了这个变量。注意,字符串类型的值一般都是由一对双引号包裹的。

    显然,在第二次赋值之前和之后,变量y的类型是不同的。虽然 Julia 允许我们随意改变一个变量的类型,但是这样做往往会对程序的性能造成不小的负面影响。所以官方在大多数情况下还是不推荐这种做法的。我们可以利用语法规则来约束对变量类型的随意变更,或者说约束赋予变量的那些值的类型。更具体地讲,我们可以在编程的时候用附加类型标识符的方式让变量的类型固定下来,比如:y::Int64

    操作符::可以将类型标识符附加到程序中的变量和表达式之后。下面是它的两个重要用途:

    1. 它可以用于类型标注,为编译器提供额外的类型信息,从而在某些情况下提高程序的性能。
    2. 它可以用于类型断言,判断某个值或者某个表达式的结果是否是某个类型的。

    3.3.1 类型标注

    当用于类型标注时,操作符::及其右侧的类型标识符就意味着这个变量将永远是某个类型的。我们赋予这个变量的每一个值都将被自动地转换为定义该变量时所声明的那个类型的值。例如,我们有这样一个函数:

    function get_uint32(x)
        y::UInt32 = x
        y
    end
    

    我先来简单地解释一下:函数的定义一般以关键字function开头,并以关键字end结尾,后者独占一行。在function右侧的是函数的名称,这两者之间需要用一个空格分隔。这里的函数名称是get_uint32。而紧挨在函数名称右侧的是由圆括号包裹的函数参数,这里唯一的函数参数是x

    在函数定义的首行和尾行之间的是函数体,可以由若干个表达式组成。并且,如果没有显式指定,那么最后一个表达式的求值结果就将是这个函数的结果。在这里,y的值就是函数get_uint32的结果。这个函数所做的事情就是,把由参数x代表的那个值赋给了局部变量y,然后把y的值作为函数结果返回。

    所谓的局部变量是指,没有直接定义在模块中而是定义在了模块包含的某个代码块中的那些变量。在上例中,我们在get_uint32函数中定义的参数x和变量y都属于局部变量。相对应的,全局变量就是直接定义在模块中的那些变量。更宽泛地讲,直接定义在模块中的变量、常量、类型、有名函数、宏和结构体可以被统称为全局程序定义。注意,这里的“全局”是针对模块而言的,而不是针对所有的代码。

    言归正传。我们没有对参数x附加类型标注,所以原则上x代表的可以是任何一个类型的值。但我们把变量y的类型声明为了UInt32。也就是说,该变量的值必须是UInt32类型的。UInt32类型是一个宽度为 32 个比特(bit)的无符号的整数类型。如此一来,当我们把x的值赋给y时,就有可能引起一个类型转换。例如:

    julia> get_uint32(2020)
    0x000007e4
    
    julia> typeof(get_uint32(2020))
    UInt32
    
    julia> 
    

    我们已经知道,整数值2020在默认情况下的类型是Int64。因此,我在调用get_uint32函数的时候把2020作为参数值传入,就一定会引起相应的类型转换。这次调用得到的结果值是0x000007e4,是一个用十六进制表示的整数值。在 Julia 中,无符号的整数值一般都是这样表示的。如果我们再把0x000007e4转换为有符号整数值的话,就会是原先的2020

    julia> Int32(0x000007e4)
    2020
    
    julia> 
    

    每一个整数类型都是有一个表示范围的。或者说,一个整数类型的值只能表示在一定范围之内的整数。比如,UInt32类型的值就无法表示负数。因此,如果我们把-2020传入get_uint32函数,就会引发一个错误:

    julia> get_uint32(-2020)
    ERROR: InexactError: trunc(UInt32, -2020)
    # 省略了一些回显的内容。
    
    julia>  
    

    从在回显内容第一行的错误信息可知,Julia 抛出了一个InexactError类型的错误。出现这类错误就意味着 Julia 无法把源值(这里是-2020)转换成目的类型(这里是UInt32)的值。另外,trunc是一个函数的名称。Julia 在这里正是使用这个函数进行类型转换的。

    当我们传入一个浮点数值、字符串值或者其他的UInt32类型无法表示的值的时候,情况也会是类似的。只不过错误的类型和具体信息可能会有所不同。

    到了这里,你可能会疑惑:为什么我们讲变量的类型标注还需要定义一个函数呢?直接在 REPL 环境中演示不就好了吗?这实际上涉及到 Julia 语言的一个小缺陷。

    在 Julia 程序中,我们无法为全局变量添加类型标注。

    还记得吗?所谓的全局变量就是直接定义在模块中的那些变量。我们编写的任何 Julia 代码都会属于某个模块。即使我们没有显式地把它们包含在某个模块中,也会是如此。更具体地讲,我们在 REPL 环境中输入的代码默认都属于Main模块。这与我们直接在源码文件中写入 Julia 代码是一样的。正因为如此,我们才能在这样的环境中仅通过名称就可以引用到之前写入的程序定义。

    由此可知,我们在 REPL 环境中直接定义附带类型标注的变量是行不通的,就像这样:

    julia> x::UInt32 = 2020
    ERROR: syntax: type declarations on global variables are not yet supported
    # 省略了一些回显的内容。
    
    julia> 
    

    一个可以绕开这个缺陷的方法是,使用Ref{T}类型的常量作为替代。“Ref”是 Reference 的缩写,可以被翻译为“引用”。Ref{T}类型本身是一个参数化的类型,其中的那对花括号就是标志。而花括号中的T表示的就是类型参数(type parameter),它在这里指代被引用的值的类型。我们可以在实际应用中自行设定这个类型。示例如下:

    julia> const xref = Ref{UInt32}(2020)
    Base.RefValue{UInt32}(0x000007e4)
    
    julia> 
    

    我使用关键字const定义了一个名为xref的常量,并把一个Ref{UInt32}类型的值赋给了它。由这个类型的字面量可知,我规定xref引用的值必须是UInt32类型的。另外,在最右侧的圆括号中的2020就是xref初始引用的值。也就是说,xref的值中又引用了另外一个值,而后者才是我们真正需要的。

    由于xref是一个常量,所以如果我们试图改变它的类型,就会引发一个错误。不过,我们仍然可以改变xref引用的值,比如:xref[] = 2050。这里的操作符[]就是用来读出或写入Ref{T}类型值所引用的值的。如此一来,我们就相当于拥有了一个具有固定类型的全局变量。关于常量的更多知识,我们到后面就会讲到。

    不过无论怎样,这终归只是绕开缺陷,而不是修补缺陷。Julia 语言的官方团队已经在计划对此进行修补了。预计在之后的某个 1.x 版本,我们就可以直接定义带有类型标注的全局变量了。

    3.3.2 类型断言

    当用于类型断言时,操作符::可以被解读为“A 是否为 B 的一个实例”。其中 A 代表该操作符左侧的值,而 B 则代表操作符右侧的类型。例如:

    julia> "abc"::String
    "abc"
    
    julia> "abc"::Char
    ERROR: TypeError: in typeassert, expected Char, got String
    # 省略了一些回显的内容。
    
    julia> 
    

    我先利用操作符::判断值"abc"是否为String类型的一个实例,并得到回显"abc"。这就说明该类型断言成功了(或者说通过了)。注意,在这种情况下,若有必要 Julia 会对::左侧的值进行类型转换,把它转换为处于::右侧的那个类型的值。这是通过调用convert函数实现的。

    之后,我又判断"abc"是否为Char类型的一个实例,并使得 Julia 报错。所以此类型断言失败(或者说未通过)。只用眼睛观察,我们就可以知道"abc"是一个字符串类型的值。而且,它并不是一个单一的字符。字符类型的值只能代表一个字符,并且需要由一对单引号包裹。

    注意,像StringChar这样的类型都属于具体类型。Julia 中还有一种类型叫做抽象类型。它们的名称很多都有着明显且一致的前缀,比如:AbstractStringAbstractChar。在进行类型断言的时候,如果右侧的类型是一个具体类型,那么只有左侧的值是该类型的一个实例,断言才会成功。而如果右侧的类型是一个抽象类型,那么只要左侧的值是这个抽象类型的任意一个子类型的实例就可以使断言成功。又由于 Julia 中的抽象类型都是不能被实例化的,因此这个子类型也必然是一个具体类型。下面看一个例子:

    julia> "abc"::AbstractString
    "abc"
    
    julia> "abc"::AbstractChar
    ERROR: TypeError: in typeassert, expected AbstractChar, got String
    # 省略了一些回显的内容。
    
    julia> 
    

    因为StringAbstractString的子类型,所以第一个类型断言成功。但是,由于String并不是AbstractChar的子类型,因此第二个类型断言失败。

    我们几乎可以把类型断言用在任何地方,只要其左侧的是一个值或是一个表达式就可以。但要注意,一旦断言失败,错误就会被抛出来。程序会因此中断,除非我们合理地处理了错误。如果我们对于某个类型断言非常没有把握,而且不想在断言失败时得到一个错误,那么可以使用isa函数作为替代。例如:

    julia> isa("abc", AbstractChar)
    false
    
    julia> 
    

    不过要注意,我们调用isa函数之后只能得到truefalse的结果。

    3.4 常量

    在 Julia 中,常量是一种特殊的变量。我们可以使用关键字const来定义一个常量:

    const A = 2020
    

    当需要同时定义多个常量时,我们还可以使用平行赋值法:

    const W, U, V = 2020, 2030, 2050
    

    在这里,常量WUV的值分别为202020302050

    我们已经知道,为全局变量附加类型标注目前是行不通的。实际上,Julia 官方现在不建议我们在程序中使用全局变量。因为全局变量总是会给程序带来不小的性能负担。这正是用于全局变量的值及其类型都是可以被随时改变的。而全局常量可以让这个问题迎刃而解。所以,我们应该使用全局常量,而不是全局变量。这也是 Julia 中很重要的一条编码建议。

    相反,在局部,我们应该使用局部变量,而不是局部常量。因为定义一个局部常量完全是没有必要的。Julia 一旦在局部碰到一个不变的变量就会把它优化成常量。你其实用不着专门去记这条编码建议。因为定义局部常量根本就不符合 Julia 的语法规则,例如:

    julia> function get_uint32(x)
               const y::UInt32 = x
               y
           end
    ERROR: syntax: unsupported `const` declaration on local variable around REPL[1]:2
    # 省略了一些回显的内容。
    
    julia> 
    

    不过,这个语法规则的制定原因我们还是应该了解的。

    另外,与其他的一些编程语言不同,Julia 中的常量的值不仅可以是数值和字符串,还可以是像数组这样的可变对象。也正因为如此,Julia 常量只能保证名称与值之间的绑定是不可变的,但是并不能防止值本身的变化,比如数组中的某个元素值的改变。所以,我们尽量不要把本身可变的值赋给全局常量。

    下面,我们来说 Julia 常量的最重要的 3 个特性。其中的一个比较反直觉的特性是:我们似乎可以改变一个常量的值。更明确地说,我们对常量的重新赋值只会引发一个警告,而不会得到一个错误。例如,我们看似可以对前面定义过的常量A进行重新赋值:

    julia> A = 2050
    WARNING: redefining constant A
    2050
    
    julia> 
    

    根据警告的内容可知,Julia 称其为对常量的重新定义。这相当于放弃了以前的常量定义,而采用了新的定义。那么,常量的重新定义与我们之前说的重新赋值到底有什么不一样呢?我们可以通过下面的示例进行理解。

    julia> const C = 2020 
    2020
    
    julia> f() = C + 30
    f (generic function with 1 method)
    
    julia> f()
    2050
    

    我先定义了一个名称为C、值为2020的常量,紧接着又用一种简洁的方式定义了一个名称为f的函数。这个函数的功能很简单,即:在常量C代表的值之上再加30并将结果返回。现在,我们重新定义常量C

    julia> C = 2030
    WARNING: redefining constant C
    2030
    

    然后,再次调用函数f

    julia> f()
    2050
    
    julia> 
    

    可以看到,调用f函数后得到的结果依然为2050。这是因为函数f使用的仍然是在它之前定义的那个常量C,而不是我们重新定义的常量C

    图 3-2 常量的重新定义
    图 3-2 常量的重新定义

    我们可以想象,如果真有一种方法可以对常量C进行重新赋值的话,那么再次调用f函数肯定不会得到这样的结果。

    因此,在 Julia 中,我们只能对常量进行重新定义,而不能进行重新赋值。正因为常量的重新定义所带来的效果有些反直觉,所以我们最好还是不要重新定义常量。为此,我们还应该让常量的名称看起来特别一些,比如全大写,以避免之后的误操作。我们还要注意程序输出中的此类警告,并及时纠正这种不好的做法。Julia 常量的第二个重要特性是,如果我们在重新定义常量的时候试图赋予它一个不同类型的值,那么就会得到一个错误。例如:

    julia> C = "2020"
    ERROR: invalid redefinition of constant C
    # 省略了一些回显的内容。
    
    julia> 
    

    注意,这里报出的错误是“对常量C的重新定义无效”,而不是“不能改变常量C的类型”。所以,这里的规则是,在对常量进行重新定义时只能赋予一个与前值类型相同的值。

    基于此,常量的第三个重要特性就比较好理解了。这个特性就是,如果在重新定义常量时赋予它相同的值,那么既不会引发警告也不会导致错误报告。比如:

    julia> const D = "2020"
    "2020"
    
    julia> D = "2020"
    "2020"
    
    julia> d = "2020"
    "2020"
    
    julia> D = d
    "2020"
    
    julia> 
    

    不过,需要注意,这只是针对不可变对象(或者说本身不可变的值)而言的。对于可变对象(比如数组),即使前后两个值看起来相同,Julia 也照样会发出警告。例如:

    julia> const E = ["2020"]
    1-element Array{String,1}:
     "2020"
    
    julia> E = ["2020"]
    WARNING: redefining constant E
    1-element Array{String,1}:
     "2020"
    
    julia> 
    

    所以,还是那句话,我们尽量不要把本身可变的值赋给常量。顺便说一下,上述代码中的字面量["2020"]表示的是只包含了一个元素值(即"2020")的一维数组。倘若一个一维数组中有多个元素值,那么我们就需要用英文逗号把这些元素值分隔开,如["2020", "2050"]

    由以上特性可知,常量看似可以被当做类型固定的全局变量来使用。但实际上,对常量的重新定义会埋下隐患,而且由此引发的程序错误将会很难排查和定位。所以,我们可以使用常量来存储全局性的对象,但最好不要对它进行重新定义。另外,我们尽量不要把可变对象赋给常量。

    3.5 小结

    我们在这一章主要讲的是变量。我们首先从可以与变量绑定在一起的对象——值——讲起。在 Julia 中,任何值都是有类型的。我们在定义一个变量的时候,可以为它添加标注类型(涉及到操作符::),也可以让 Julia 自行推断其类型。我们推荐前者的做法,因为那样做会对程序的性能有好处。不过要注意,我们是无法为全局变量添加类型标注的。

    代表变量的标识符、赋值符号=和代表值的字面量共同组成了变量的定义。它把一个值与一个标识符(或称变量名)绑定在了一起。此后,这个标识符就是那个值的代表。

    Julia 对变量名有所限制,但是这种限制还是很宽松的。大部分 Unicode 字符都可以被包含在内。不过,变量名不能与 Julia 中任何一个单一的(或者说单词的)关键字重复,也不能与处在同一个作用域中的其他程序定义的名称重复。

    一旦理解了变量,常量的概念就很好理解了。因为 Julia 的常量就是一种特殊的变量。只不过,常量只能被定义在全局,而不能被定义在局部。另外,我们需要特别注意对常量的重新定义。

    除了上述知识,我们还在本章顺便说明了程序定义、代码块、作用域等概念的含义。你最好记住它们,因为我们在后面还会有所提及。

    值、变量以及类型是 Julia 中最基础的概念。没有了它们,我们就无法编写 Julia 程序。别着急,我们马上就会讲到第三个基础概念——类型。

    展开全文
  • 以小写字母或下划线开头的标识符在 Ruby 中即为局部变量(如果引用未被声明的标识符则会被解释成无参数的方法调用)。 val = 5 if false 虽然 val 未被赋值,但声明还是有效的,此时 val 的值 nil(相当于 C# 中...
  • Ruby 入门: 变量常量

    2006-04-18 09:31:00
    以小写字母或下划线开头的标识符在 Ruby 中即为局部变量(如果引用未被声明的标识符则会被解释成无参数的方法调用)。 val=5iffalse 虽然 val 未被赋值,但声明还是有效的,此时 val 的值 nil(相当于 C# 中的 ...
  • *const声明一个只读的常量。一旦声明,常量的值就不能改变。...1) 不管let还是const,都没有了变量声明的提升; console.log(m); //报错,没有变量声明的提升; let m = 100; 2) 不管let还是const,babe...
  • 被final修饰的变量其实就相当于定义了一个常量,无法被修改的变量: 如果final修饰的是一个基本数据类型的变量,那么这个变量的值就定了,不能变了, ...还有的人给方法定义的参数是 final类型的,是不想别人在方...
  • 有的内存地址.(原文传递的都栈里的的值有误,局部变量在栈中,成员变量在堆中,类变量(静态变量常量)在方法区中,可以看做本文的变量main方法下的变量)基本类型的栈 它的本身. 传递时.传递的本身的...
  • 有的内存地址.(原文传递的都栈里的的值有误,局部变量在栈中,成员变量在堆中,类变量(静态变量常量)在方法区中,可以看做本文的变量main方法下的变量) 基本类型的栈 它的本身. 传递时.传递的本身...
  • 使用常量初始化引用

    千次阅读 2018-07-10 00:23:15
    引用是变量的别名,使用常量初始化引用错误的,如int &amp;a=10;那么如何使用常量初始化引用呢?需要使用常量引用:const int &...常量引用在函数声明时的作用还是非常明显的,如果将函数的参数...
  • Java 字符串常量池到底在PermGen方法区、在heap堆里面、还是在Metaspace 元空间里面呢? 2.基本数据类型与引用数据类型 int num = 10; double dec = 1.23; 上述基本类型在内存中这样的: int[][] twoDim ...
  • VC 对 memcpy 的优化

    千次阅读 2013-07-05 18:17:36
    在很多编译器中,memcpy 是一个 intrinsic 函数,也就是说,这个函数是由编译器实现的。...编译器可以根据 memcpy 的参数是常量还是变量做出多种版本,达到最佳的性能。这一点,用 inline 或者 template 的技巧都无法
  • Java学习之参数传递1. 简单Java类2. 堆、栈及常量池2.1 常用概念3. 关于字符串3. 关于基础类型的变量4. 值传递与引用传递4.1 值传递4.2 引用传递5. 优秀的博客 1. 简单Java类 类名称一定要有意义,可以明确表示或...
  • 1、引用、常量引用 引用主要被用做函数的形式参数--通常将类对象传递给一个函数. 引用在内部存放的一个对象的地址,它该对象的别名。引用不占用内存,因为取地址引用的值和被引用变量的地址相同。但是objdump ...
  • Java参数传递——值传递还是址传递? 首先是变量的存储方式 各种变量的存储方式: 基本数据类型: int age = 20; 变量名age和值20都存储在jvm栈中 引用数据类型: 字符串见 ...
  • window环境变量

    2019-03-08 09:50:52
    环境变量(environment variables)一般指在操作系统中用来指定操作系统运行环境的一些参数,例如指定系统文件夹或临时文件夹的位置等。与常量相比,一个环境变量往往由变量名称和变量值组成,环境变量名称和数值...
  • “自动存储区”还是“静态存储区”中? 比如: char *pstr=“hello world!”; 这里,"hello world!"一个字符串常量, pstr在栈中的变量。 我想问,字符串常量,在哪个内存区域分配空间呢? 好像应该不是在“栈...
  • 宏和常量到底选择什么?

    千次阅读 2018-05-28 21:46:06
    通常情况下不管声名字符串还是函数其作用主要有两个: 1.增强代码可读性 2.方便全局使用和修改一些方法和参数 3.增强复用性 命名规范 Tips: 1.通常情况下,习惯将预处理的常量名全大写,单词之间用下划线隔开...
  • “自动存储区”还是“静态存储区”中? 比如: char *pstr=“hello world!”; 这里,"hello world!"一个字符串常量, pstr在栈中的变量。 我想问,字符串常量,在哪个内存区域分配空间呢? 好像应该不是在“栈...
  • const 修饰的变量只读的,本质还是变量 const 修饰的局部变量在栈上分配空间 const 修饰的全局变量在全局数据区分配空间 4. const 只在编译器有用,在运行期无用 const 修饰的变量不是真的常量,它只是告诉...
  • 单引号''是全引用,被单引号括起的内容不管是常量还是变量者不会发生替换。 双引号: 把双引号内的内容输出出来;如果内容中有命令、变量等,会先把变量、命令解析出结果,然后在输出最终内容来。双引号""是...
  • 函数的参数

    2019-09-26 12:22:19
    实参可以是常量变量,表达式,函数等,但都必须有确定的值,应该预先赋值,再带入实参。 默认参数 如果函数定义中有默认参数,实参中没有该默认参数,调用形参时会带入默认参数。(下面函数c 的Country还是USA)...
  • 先不要太关注参数到底值传递还是引用传递,抛开这个想法,先搞清楚Java中值、对象、对象的引用怎么存储的? 栈:存放8种基本数据类型的变量和对象的引用(对象的引用保存的只是对象本身的地址),对象本身不...
  • C语言中const关键字constant的缩写,通常翻译为常量、常数等,有些朋友一看到const关键字马上就想到了常量。事实上在C语言中const功能很强大,它可以修饰变量、数组、指针、函数参数等。本文将针对上述几种修饰...
  • ****在C++中,内存管理一件十分让人畏惧的事,要考虑的...分配的变量主要参数,函数内定义的局部变量,由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。**** 堆: 主要用new操作符来定义...
  • 可以修饰变量,方法,方法中的参数,修饰类修饰变量时 用final关键字修饰的变量,只能进行一次赋值操作,并且在生存期内不可以改变它的值。其中的只能进行一次赋值操作发生在编译期间还是发生在运行时期间?如果...
  • 不变参数是在内存中有对应的常量数据区,也就是说一开始定义的数据,不管是其所指的地址还是该地址所指的值都是不可变的; 而我们所说的变量,也就是可变参数,则包括值变量和指针变量,但其本身的地址是固定的,...

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 277
精华内容 110
关键字:

参数是常量还是变量