前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Julia机器核心编程.多重分配

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

作者头像
云深无际
发布2020-09-03 17:27:35
1.1K0
发布2020-09-03 17:27:35
举报
文章被收录于专栏:云深之无迹云深之无迹

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

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

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

• 静态分派:在编译时定义分派的顺序。事实上,在静态分派中,在程序执行之前所有类型都是已知的。编译器能够为每种可能的数据类型组合生成特定的代码,并提前知道它们的使用时间和位置。这是大多数语言中最常用的一种分派方式。举例来说,如果我们在代码的某个位置使用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函数可以接收两个参数,第一个参数是要转换成的数据的类型;第二个参数是准备转换的数据。

代码语言:javascript
复制
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_num2
05      end
06  add_numbers (generic function with 1 method)
07
08  julia> add_numbers(4,6)
09  10.0

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

对两个浮点数求和

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

代码语言:javascript
复制
01  julia> function add_numbers(num1::Float64, num2::Float64)
02        return num1+num2
03      end
04  add_numbers (generic function with 2 methods)
05
06  julia> add_numbers(222.0,333.0)
07  555.0

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

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

method函数的使用

代码语言:javascript
复制
01  julia> methods(add_numbers)
02  # 2 methods for generic function "add_numbers":
03  [1] add_numbers(num1::Float64, num2::Float64) at REPL[2]:2
04  [2] add_numbers(num1::Int64, num2::Int64) at REPL[1]:2

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档