当前位置:K88软件开发文章中心编程语言非主流编程语言Julia → 文章内容

Julia 代码样式

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 16:28:33

由 陈 创建, 最后一次修改 2016-08-12 代码样式以下各节从几方面介绍了符合语言习惯的 Julia 编码风格。这些规则都不是绝对的;它们仅仅是帮您熟悉这门语言,或是帮您可以在许多可替代性设计中能够做出选择的一些建议而已。写成函数,别写成脚本编写代码作为在一系列步骤中最高级的办法,是可以快速开始解决问题的,但您应该试着尽快把一个程序分成许多函数。函数具有更好的可重用性和可测试性,并可以更好阐明它们正在做什么,它们的输入和输出是什么。此外,由于 Julia 的编译器工作原理,在函数中的代码往往比最高级别的代码运行得更快。同样值得强调的是,函数应该以参数来代替,而不是直接在全局变量(除了像 pi 那样的常量)上操作。避免类型过于严格代码应尽可能通用。相较于这样的代码书写: convert(Complex{Float64}, x)使用有效的泛型函数是更好的: complex(float(x))第二种写法把 x 转换成一个适当的类型,而不是一直用一个相同的类型。这种类型特点是特别地与函数自变量相关。例如,不声明一个参数是 Int 类型或 Int32 类型,如果在这种情况下还可以保持是任何整数,那就应该是用 Integer 抽象表达出来的。事实上,在许多情况下您都可以把自变量类型给忽视掉,除非一些需要消除歧义的时候,由于如果一个类型不支持任何必要操作就会被忽略,那么一个 MethodError 不管怎样也都会被忽略掉。(这被大家认为是 duck typing。)例如,考虑以下 addone 函数中的定义,这个功能可以返回 1 加上它的自变量。 addone(x::Int) = x + 1 # works only for Int addone(x::Integer) = x + one(x) # any integer type addone(x::Number) = x + one(x) # any numeric type addone(x) = x + one(x) # any type supporting + and one最后一个 addone 的定义解决了所有类型的有关自变量的 one 函数(像 x 类型一样返回 1 值,可以避免不想要的类型提供)和 + 函数的问题。关键是要意识到,仅仅是定义通用的 addone(x) = x + one(x) 写法也是没有性能缺失的,因为 Julia 会根据需要自主编译到专业的版本。举个例子,您第一次调用 addone(12) 的时候, Julia 会自动为 x::Int 自变量编译一个 addone 函数,通过调用一个内联值 1 代替 one。因此,上表前三个定义全都是重复的。在调用程序中解决额外的自变量多样性问题取代这种写法: function foo(x, y) x = int(x); y = int(y) ... end foo(x, y)利用以下的写法更好: function foo(x::Int, y::Int) ... end foo(int(x), int(y))第二种写法更好的方式,因为 foo 并没有真正接受所有类型的数据;它真正需要的是 Int S。这里的一个问题是,如果一个函数本质上需要整数,可能更好的方式是强制调用程序来决定怎样转换非整数(例如最低值或最高值)。另一个问题是,声明更具体的类型会为未来的方法定义提供更多的“空间”。如果函数修改了它的参数,在函数名后加 !取代这种写法: function double{T<:Number}(a::AbstractArray{T}) for i = 1:endof(a); a[i] *= 2; end a end利用以下写法更好: function double!{T<:Number}(a::AbstractArray{T}) for i = 1:endof(a); a[i] *= 2; end a endJulia 标准库在整个过程中使用以上约定,并且 Julia 标准库还包含一些函数复制和修饰形式的例子(例如 sort 和 sort!),或是其它只是在修饰(例如 push!, pop!,splice!)的例子。这对一些也要为了方便而返回修改后数组的函数来说是很典型的。避免奇葩的类型集合像 Union(Function,String) 这样的类型,说明你的设计有问题。尽量避免空域当使用 x::Union(Nothing,T) 时,想想把 x 转换成 nothing 这个选项是否是必要的。以下是一些可供选择的替代选项找到一个安全的默认值来和 x 一起初始化介绍另一种缺少 x 的类型如果有许多类似 x 的域,就把它们存储在字典中确定当 x 是 noting 时是否有一个简单的规则。例如,域通常是以 nothing 开始的,但是是在一些定义良好的点被初始化。在这种情况下,要首先考虑它可能没被定义。避免复杂的容器类型通常情况下,像下面这样创建数组是没什么帮助的: a = Array(Union(Int,String,Tuple,Array), n)在这种情况下 cell(n) 这样写更好一些。 这也有助于对编译器进行注释这一特定用途,而不是试图将许多选择打包成一种类型。使用和 Julia base/ 相同的命名传统模块和类型名称以大写开头, 并且使用驼峰形式: module SparseMatrix,immutable UnitRange.函数名称使用小写 (maximum, convert). 在容易读懂的情况下把几个单词连在一起写 (isequal, haskey). 在必要的情况下, 使用下划线作为单词的分隔符. 下划线也可以用来表示多个概念的组合(remotecall_fetch 相比 remotecall(fetch(...)) 是一种更有效的实现), 或者是为了区分 (sum_kbn). 简洁是提倡的, 但是要避免缩写(indexin 而不是 indxin) 因为很难记住某些单词是否缩写或者怎么缩写的.如果一个函数需要多个单词来描述, 想一下这个函数是否包含了多个概念, 这样的情况下最好分拆成多个部分.不要滥用 try-catch避免错误要比依赖找错好多了。不要把条件表达式用圆括号括起来Julia 在 if 和 while 语句中不需要括号。所以要这样写: if a == b来取代: if (a == b)不要滥用 ...剪接功能参数可以让人很依赖。取代 [a..., b...] 这种写法,简单的 [a, b] 这样写就已经连接数组了。collect(a) 的写法要比 [a...] 好,但是因为 a 已经是可迭代的了,直接用 a 而不要把它转换到数组中也许会更好。不要使用不必要的静态参数信号函数: foo{T<:Real}(x::T) = ...应该这样写: foo(x::Real) = ...特别是如果 T 没被用在函数主体。即使 T 被用在函数主体了,如果方便的话也可以被 typeof(x) 替代。这在表现上并没有什么差异。要注意的是,这不是对一般的静态参数都要谨慎,只是在它们不会被用到时要特别留心。还要注意容器类型,特别是函数调用中可能需要的类型参数。可以到 FAQ 如何声明“抽象容器类型”的域 来查看更多信息。避免对实例或类型判断的困扰一些如以下的定义是十分让人困扰的: foo(::Type{

[1] [2]  下一页


Julia 代码样式