Julia机器核心编程.多重分配

在开始深入探讨多重分派这个主题之前,我们先问自己一个简单的问题:分派到底是什么意思?用最简单的术语来解释,分派的意思就是发送!

在编程术语中,分派意味着向监听器发送一条消息或者调用一个函数。基本上就是将一段数据(或信息包)发送给准备用来处理它的代码。

分派有多种不同的类型,下面列举出其中的一部分:

· 静态分派:在编译时定义分派的顺序。事实上,在静态分派中,在程序执行之前所有类型都是已知的。编译器能够为每种可能的数据类型组合生成特定的代码,并提前知道它们的使用时间和位置。这是大多数语言中最常用的一种分派方式。举例来说,如果我们在代码的某个位置使用funct()或x.funct()调用函数或者方法,那么每次都会调用相同的函数或者方法,不会有任何变化

· 动态分派:可以在运行时定义分派顺序,这就意味着编译器必须拥有一个包含所有已定义函数的查找表,然后确定运行时实际调用哪些函数。用代码解释的话,假设有类classA和classB,并且它们各自都有一个名为foo()的函数实现,那么在运行时将检查这两个类,最后classA.foo()和classB.foo()的其中一个将会被调用。

· 多重分派:在多重分派中,分派顺序取决于函数名称以及所传递的参数类型,即函数的签名和被调用的实际实现是在运行时直接确定的。用代码解释的话,假设有一个类classA,它实现了一个方法foo(int),参数类型是一个整数,同时实现了另一个方法foo(char),参数类型是字符型。接下来,我们在程序中使用classA.foo(x)进行一次函数调用,在运行时检查将classA和x的类型,从而确定究竟应该调用哪一个foo()函数。

Julia支持多重分派,下面探讨Julia是如何实现此技术的。

方法是Julia生态系统中非常重要的一部分,为了更好地理解多重分派是什么,以及Julia使用多重分派的原因,我们首先需要知道方法是什么。

假设有一个对两个数字求和的函数。范例如下:

代码01~03行定义了求和函数,传入的参数类型被限制为整型。

这里我们定义了add_numbers()函数,它可以接收两个整型参数。当调用add_numbers(1,2)函数时,我们将会得到以下结果:

int64


就和我们预期的结果一样,1+2=3。另外,我们注意到ans的类型,也和所预期的一样是Int64。

但是如果不小心给函数传递了浮点数:

Julia将抛出一个错误!为什么?

答案很简单,因为在函数体中已经明确定义了会传递给add_numbers()函数两个Int64类型的参数。如果没有明确定义这两个参数必须是整数类型,那么就不会抛出错误,如下所示。

这似乎与Python中的函数用法非常相似,在Python中我们只是定义函数,并没有指定参数的类型,而是将推理参数类型的工作留给了Python解释器来做,Julia在这里所做的工作和Python解释器是一样的。

但是,这是否意味着我们之前对参数进行明确的类型定义是错误的呢?答案是否定的!

给函数指定所期望的参数类型会使它们运行得更快,因为编译器不用再推断提供给函数的参数的类型了。记住自己的写法,会提升性能,减少开销通过指定参数类型不仅可以防止编译器浪费时间,而且还可以获得速度上的提升。

我们回到函数add_numbers(num1::Int64,num2::Int64)上,在保证输入参数的类型是整数的情况下,如果想要这个函数返回一个Float类型的对象,该怎么办呢?一种方法是使用convert函数,它会对所传入的参数进行类型转换。convert函数可以接收两个参数,第一个参数是要转换成的数据的类型;第二个参数是准备转换的数据。

01 julia> function add_numbers(num1::Int64, num2::Int64)02 float_num1 = convert(Abstract Float, num1)03 float_num2 = convert(Abstract Float, num2)04 return float_num1+float_num205 end06 add_numbers (generic function with 1 method)0708 julia> add_numbers(4,6)09 10.0

结果是正确的,但不是我们想要的。我们想要的是,即使提供了Float参数,也可以让add_numbers函数起作用。为了解决这个问题,我们再定义一个处理Float64类型数据的方法。

对两个浮点数求和

本例中定义了add_numbers函数用来对两个浮点数求和。

01 julia> function add_numbers(num1::Float64, num2::Float64)02 return num1+num203 end04 add_numbers (generic function with 2 methods)0506 julia> add_numbers(222.0,333.0)07 555.0

与对两个整数求和的函数的唯一区别就是,我们限制所传入的参数类型为浮点型。如果细心的话,我们会发现在代码04行第一次出现了(generic function with 2 methods)。这是因为这两个函数是同名函数,只不过所传入的参数不同,那么这时新构建的用于计算两个浮点数的和的函数,就会自动成为add_numbers函数下的一个子方法。同时,之前定义的计算两个整数的函数也会变成一个子方法,这两个方法共享add_numbers函数名。

要查看函数自身的所有方法,我们可以使用methods函数。

method函数的使用

01 julia> methods(add_numbers)02 # 2 methods for generic function "add_numbers":03 [1] add_numbers(num1::Float64, num2::Float64) at REPL[2]:204 [2] add_numbers(num1::Int64, num2::Int64) at REPL[1]:2

仔细观察输出结果,它列出了到目前为止我们为函数定义的所有方法,包括处理两个整型参数的方法和处理两个浮点型参数的方法。

像这种多个子方法对应相同的函数名,并在调用时自动由Julia根据所传递的参数类型来调用相应方法的机制,就是我们所说的多重分派。


(0)

相关推荐

  • 为什么指针被誉为 C 语言灵魂?

    来自公众号:编程指北 是的,这一篇的文章主题是「指针与内存模型」 说到指针,就不可能脱离开内存,学会指针的人分为两种,一种是不了解内存模型,另外一种则是了解. 不了解的对指针的理解就停留在" ...

  • 基础语法第2关笔记

      一.Python 核心知识框架 Python 的核心知识板块包括:数据类型,控制流,函数,模块,类.   数据类型:程序本质上是在操作和处理数据,Python 中所有数据都属于某种数据类型 ...

  • Julia机器核心编程.5

    julia的浮点数 bits这个函数好像没有了,我xiang给你看下这个值 的二进制表示在最全面的符号位不同 指数形式的浮点数 代码01行使用f代替e来表示这是一个Float32类型的值.代码03行使 ...

  • Julia机器核心编程.函数

    函数是任何编程语言都不可缺少的一部分,因为函数对功能进行模块化封装,提高了程序的可读性和可重用性.Julia也不例外,它不仅提供了一些内置的库函数,同时也允许用户自定义函数. 在Julia中使用fun ...

  • Julia机器核心编程.7

    可以说,无论是R(data.frame)还是Python(Pandas)中的表格都是统计计算中最重要和最常用的数据类型.这是因为真实世界中的数据大多是表格式的,不能用简单的DataArray来表示. ...

  • Julia机器核心编程.高阶函数

    我这个起名好麻烦,都说函数完了.有整出来一个高阶函数,比较麻烦. 嵌套函数,简单来说,就是在函数中定义函数. 闭包是一个函数对象,它可以记住封闭范围中的值,即使它们不在内存中也是如此. 嵌套函数有助于 ...

  • Julia机器核心编程.作用域

    当我们在Julia中定义函数时,也可以在函数体内定义变量.在这种情况下,该变量在该函数的局部范围内有效,因此称为局部变量.而未在函数体内声明的变量在全局范围内有效,因此称为全局变量. 不同代码块中的变 ...

  • Julia机器核心编程.函数(完)

    当我们讨论函数时,一个非常重要的方面就是参数.毫无疑问,在其他语言中几乎都使用过参数,并且参数可以通过值或者引用传递. 但是Julia却不同,在Julia中参数是通过分享传递的.为了搞清楚什么是分享传 ...

  • Julia机器学习核心编程.1

    其实这个地方是应该有一个juliahitory的目录的,可是没有 只能曲线救国,这样搜索的用了 Ctrl+R 在终端里面搜索用过的命令 shift+?进入帮助模式 分号进入shell模式 报错打脸了 ...

  • Julia机器学习核心编程.4

    在win上加e参数,执行这个代码.不可以.类unix可以试试,我有空操作 我超级喜欢这种循环写法 我这个传参写法没有错,不知道这么久没有出来 与其他编程语言一样,Julia可以更改存储在变量中的值或改 ...

  • Julia机器学习核心编程.3

    一般来说,解决问题的思路是先找出问题的来源,然后将问题分解成若干个小问题逐一解决.同时,还需要考虑所有情况,以保证该方法能完整地解决问题.而编程范式就是一种将编程活动分解的思想,虽然编程范式有很多种, ...