一个简单的Julia教程
原文链接:点击打开链接
摘要: 当前版本 v0.5 因为在知乎上写的量子计算札记会涉及到使用Julia语言的数值模拟,同时随着中国的Julian越来越多,而之前几个在JuliaCN活跃的老司机最近一直没时间翻译文档,然后最近好像也没什么人给贡献翻译OTZ。
当前版本 v0.5
因为在知乎上写的量子计算札记会涉及到使用Julia语言的数值模拟,同时随着中国的Julian越来越多,而之前几个在JuliaCN活跃的老司机最近一直没时间翻译文档,然后最近好像也没什么人给贡献翻译OTZ。所以呢,先写一个简单的教程给大家用。有很多地方参考了英文的标准文档。感兴趣的同学可以直接戳英文文档,也欢迎大家给中文文档贡献翻译。极客学院上也有一些教程,你也可以参考那个。知乎好像没Julia高亮or我哪里没有设置对,如果有强迫症可以戳我blog上的:一个简单的Julia教程|Half Integer
声明这个教程应该适用于已经学过一门编程语言,想快速掌握Julia语法的人。所以
Hello World!
使用Julia的解释器
我们可以新建一个脚本文件hello.jl,在里面写
print("hello world\n")
我们先不要管这行命令具体是怎么回事,你知道它是用来打印Hello World的就可以啦。然后在命令行里用Julia的解释器执行它
$ julia hello.jl
hello world
使用REPL环境
或者让我们打开Julia的REPL
- Linux/Mac:在命令行里输入julia
- Windows:双击Julia的可执行文件或者快捷方式
然后你就进入到了一个交互式的窗口中,输入这个打印Hello World的命令
julia> print("hello world!\n")
hello world!
那么这个print函数是干嘛的呢?我们可以在REPL中输入?+print+enter来获得它的文档
julia>
help?>print
search: print println print_joined print_escaped print_shortest print_unescaped
print(x)
Write (to the default output stream) a canonical (un-decorated) text
representation of a value if there is one, otherwise call show. The
representation used by print includes minimal formatting and tries to avoid
Julia-specific details.
那么我们就知道了print是说打印输入的变量的意思
用-e选项执行代码
安装好Julia之后,按Ctrl+Shift+T打开命令行(Windows用户请按Ctrl+X,点击运行输入cmd,打开命令行),可以直接运行Julia命令。
$ julia -e 'print("hello world!\n")'
hello world!
这是Julia的第一种执行命令的方式,-e 选项后面用'括起你要执行的Julia代码,但注意因为回车会让命令行执行这行命令所以你必须把所有的代码写成一行。一般我们只用这种方式执行一些很短的,很简单的代码。
变量
让我们打开一个REPL,在里面测试这一小节的内容。首先,Julia的变量不需要特别的声明,变量类型会由你所给它的值自动确定
# 将10赋值给变量x
julia> x=10
10
# 对变量x进行运算
julia> x+1
11
# 重新给x赋值
julia> x= 1+1
2
# 但是请不要用数字作为变量名的开头,因为Julia中默认数字开头代表了乘法
julia> 2x
4
# 也可以给x赋其它类型的值
julia> x = "hello world!"
hello world
Julia的变量名称支持大部分的Unicode(有极少数的不能支持,但我们不需要管),所以你可以这样
julia> δ = 0.00001
1e-5
julia> 你好 = "hello"
hello
这些数学符号可以使用LaTeX语法输入,中文的话用你自己的输入法就可以啦,Julia支持了包括UTF-8在内的多种编码。在REPL中可以这样输入一个希腊字母\delta+Tab = δ, 而在编程的时候我们当然不能用命令行,所以有这样几个编辑器支持这种补全(如果你发现还有别的好用的编辑器不妨在评论里告诉我):
- Atom+Juno 目前最好用的Julia IDE
- sublime+SublimeLinter-contrib-julialint
Julia有一些自带的常量,这些常量是允许重载的,但是一般不建议重载它们。比如
julia> pi
π = 3.1415926535897...
julia> pi = 3
WARNING: imported binding for pi overwritten in module Main
3
julia> π
3
整数和浮点数
整数从8位整数支持到128位整数,而浮点数从16位支持到64位浮点数,如果有高精度计算需求还可以使用内建的高精度浮点数BigFloat(256位),整数Int默认跟随系统位数,比如在32位系统上为32位整数类型Int32,但64位系统就是Int64
Tips:
- 浮点数的精度可以用函数eps求出,比如eps(Float32)
- 比较长的数字可以用_来分割,比如100_101,1000_1010,相当于计数法中的逗号:100,101 1000,1010
复数和分数
在Julia中,虚数单位用im来表示,Julia为虚数对象定义了一些基本的函数
julia> 1+2im
1 + 2im
# 实部
julia> real(1+2im)
1
# 虚部
julia> imag(1+2im)
2
# 共轭
julia> conj(1+2im)
1 - 2im
# 取模
julia> abs(1+2im)
2.23606797749979
julia> norm(1+2im)
2.23606797749979
# 求幅角
julia> angle(1+2im)
1.1071487177940904
运算符
Julia中定义了一些常用的运算符,它们有
数学算符和基本函数
Tips:
- Julia中可以使用更加自然的不等式表达方式,比如1<x<2,而不用写成x>1 and x<2(python) 或者 (x>1)&&(x<2)(类C)
语句
Julia的语句可以默认以一行结尾,比如
x+1
y+2
这里x+1和y+1就是分割开的两条语句,但是我们也可以用;分割语句,比如
x+1;y+1
z+2
Julia的代码块都以end关键字结尾,类似于Pascal,相当于C/C++中的{}声明代码块的方式。也相当于Python中使用空格对齐来分割代码块。
类型系统
Julia的类型系统是很有特点的,也常常被认为是Julia的速度快的原因之一。Julia的类型系统不支持类似于Python/Cpp那样以对象的成员函数和继承构成的OOP编程范式。Julia中面向对象的编程使用了Multiple Dispatch这一特性,而禁止了类型(对象)中使用成员函数。这种特性继承自Lisp,称为OO,而多重派发是实现OO的一个重要手段。
具体关于OO技术的好处可以参看这篇博客:浅谈OO编程中必不可少的手段:Multimethod,关于类似于Cpp这种面向对象编程的弊端可以参见这个知乎问题:面向对象编程的弊端是什么
Julia中总共提供了四种类型,它们的关键字分别是:type,immutable,abstract,bittype,这里我们暂时只介绍前三种(最后)
复合类型(对象)
在Julia中使用type关键字声明复合类型,以end关键字结尾。在type和end之间声明此类型所包含的变量
type Animalweightsex
end
当然也可以用分号来分割语句
type Animal
weight;sex
end
当然你也可以什么都不写,但这种时候建议你最好考虑一下后面介绍到的抽象类型。
type Animal
end
用type声明的类型在没有说明的时候默认以指针赋值,或者说默认使用引用的方式来赋值。除非使用deepcopy函数显式说明是深度拷贝。
复合类型中的元素可以通过.运算符来访问
julia> alpaca = Animal("肥的","母的")
Animal("肥的","母的")
julia> alpaca.sex
"母的"
指定类型和限定类型
Julia是一个强类型语言,我们可以用::符号来声明(或者标注)变量类型,比如
julia> (1+2)::AbstractFloat
ERROR: TypeError: typeassert: expected AbstractFloat, got Int64julia> (1+2)::Int64
3
在复合类型中
type Animalweight::Float64sex::Int
end
指定类型往往能够让Julia程序的运行效率更高。
抽象类型
抽象类型使用abstract关键字声明,声明抽象类型一般有什么用呢?声明抽象类型可以很好的帮助你控制接口,具体的例子我们在后面的多重派发介绍。
abstract AbstractAnimal
抽象类型可以作为其它类型的父类型出现,比如
abstract Monkey <: AbstractAnimal
这里<:运算符代表:左边是右边的子类型,它可以在声明的时候使用,也可以用来做类型判断
julia> Monkey <: AbstractAnimal
true
复合类型也可以作为抽象类型的子类型,但不能作为复合类型的子类型。
type Donkey <: AbstractAnimal
alive::Bool
end
Tips:
- 那么所有Julia类型的父类型是什么呢?是Any
不可变类型
immutable Complexreal::Float64imag::Float64
end
不可变类型是一种类似于type的类型,但是相对type有一些不同:
- 有些时候性能更好这个具体是说当变量所占内存较少的时候,比如像上面的Complex,相对type声明的类型能够更有效的打包进数组中,在一些时候编译器能够避免为整个immutable类型分配内存。
- immutable中的变量是不能够被改变的
- 使用immutable的代码更容易理解
注意,不可变类型中的元素如果是可变类型的,比如数组,那么这个元素依然是可变的
immutable Animalslist_of_animals::Array
end
这里list_of_animals是可以改变的,但是Animals不能够被改变
julia> animals = Animals([1,2,3])
Animals([1,2,3])
julia> another_list = [2,3,4]
3-element Array{Int64,1}:
2
3
4# Animals的元素不能改变
julia> animals.list_of_animals = another_list
ERROR: type Animals is immutable# 但是Animals元素的元素可以改变
julia> animals.list_of_animals[2] = 100
100
julia> animals.list_of_animals
3-element Array{Int64,1}:
1
100
3
产生类型的实例
复合类型type和不可变类型immutable都可以用如下的方法产生实例
type foo1ab
endfoo1(1,2)immutable foo2ab
endfoo2(2,3)
参数输入的顺序是每个类型的元素在类型中的顺序
参数类型
Julia的类型也有类似于C++的模板(template)的功能,比如假如现在有Monkey,Donkey,Pig这样三个类型,都是AbstractAnimal的子类型。但是我想有一个Pet(宠物)类型,我可以养猴子,也能养驴,还能养猪当宠物,所以不能给Pet的成员指定某个类型,但我又不希望它被用来装别的类型。所以这个时候就需要参数类型。
type Monkey<:AbstractAnimal
endtype Donkey<:AbstractAnimal
endtype Pig<:AbstractAnimal
end
type Pet{T<:AbstractAnimal}p::T
end
这样在生成这个类型的实例的时候,编译器就会生成相对应的类型,比如
julia> Pet{Monkey}(Monkey())
Pet{Monkey}(Monkey())
注意参数类型在产生实例的时候需要指定参数,编译器不会自己判断,当然我们有办法让编译器自己判断,这个在后面介绍。
Tips
除了类型意外,参数类型的参数还可以是别的东西,比如一个数字
type foo{N}
endjulia> foo{2}()
foo{2}()
函数
在Julia中函数使用function关键字来声明
function add(a,b)return a+b
end
返回值由return关键字指定,或者由最后一个变量指定
function foo()"foo"
endjulia> foo()
"foo"
实际上对于比较短的函数,你还可以这样声明
f(x) = x^2julia> f(2)
4
构造函数
构造函数是用于定义如何构造对应类型的方法的函数。类似于其它面向对象语言,Julia的复合类型也有构造函数,并且是唯一可以在类型内声明的函数。构造函数默认是下面这样的,也就是需要按照内部元素的顺序来构造一个新的foo对象。
type foo
a::Int
b::Float64
endf = foo(1,1.0)
实际上它相当于
type foo
a::Int
b::Float64foo(a::Int, b::Float64) = new(a, b)
end
Julia的构造函数分为两种,一种是类型内的构造函数,一种是类型外的构造函数。类型外的构造函数实际上都是调用默认的构造函数创建对象,与一般的函数类似。而类型内的构造函数略有不同,类型内的构造函数可以访问new函数来为新对象的元素绑定值。new是一个用来给类型元素绑定值的函数,注意这个函数仅有在类型内的构造函数声明才能够访问。
lambda 表达式
lambda表达式可能会是我们很常用的一种函数,它也往往称为匿名函数,匿名函数的声明有两种方式
# 第一种
x->x^2+1
# 第二种
function (x)return x->x^2+1
end
第一种声明方式后面需要跟一整个代码块,julia中可以使用begin,end来声明一段代码块(不过这个应该要算在metaprogramming的部分了?)
所以你可以这样
x->beginif x == "蛤?"return 1elsereturn "excited"endend
而很多时候,我们都需要将匿名函数作为某个函数的第一个变量输入,比如像map,sum这种的。这个时候再写
map(x->beginif x == "蛤?"return 1elsereturn "excited"endend, [1, "蛤?", 2])
未免有些不美观,影响可读性,尤其是里面这个匿名函数比较复杂的时候。不用担心,julia为这种比较长的匿名函数提供了一个可读性更好的声明方式
map([1, "蛤?", 2]) do xif x == "蛤?"return 1elsereturn "excited"end
end
do关键字会产生将后面的代码块(到end结束)创建成一个匿名函数然后传递给do前面的函数的第一个变量,比如map。有了这个特性,类似于Python的with关键字,我们在Julia中操作文件的时候也可以让它自动关闭
open("outfile", "w") do iowrite(io, data)
end
循环和判断
和其它的编程语言类似,尤其是和python类似,julia的for和while也有很多语法糖。
比如
for i = 1:10
@show i
end
for i in [1,2,3,4,5,6,7,8,9]
@show i
end
等等。然后if,else语句类似于Python,但Python的elif变成了elseif
if x>0println(1)
elseif x == 0println(0)
elseprintln(3)
end
同时也支持expr?a:b形式的简写,意思是expr为true则执行a,false执行b
模块和包管理
Julia的名字空间是通过模块module来进行管理的。
module foo
export foo1, foo2
############
# content
############
end
在module和end关键字中的代码块就会记在这个module下,使用的时候必须先将相应的module所开放的(export)的名字引入,方法有两种,一种是using,一种是import
using会将后面的模块中所有开放的变量暴露在当前的空间中,而import会引入相应的模块名称。举个例子,我使用QuDynamics这个模块的时候,如果
using QuDynamics,那么其中所开放的函数我都可以直接访问,比如propagate这个函数,我就可以直接使用它。而相应的import QuDynamics,就需要用.运算符访问模块的元素,也就是这个模块所开放的接口,例如QuDynamics.propagate
而Julia的package都是会由一个module进行封装,在安装的时候需要知道相应包的名字,比如Plots,然后使用Pkg.add命令进行安装。例如Pkg.add("Plots")。之后Julia的编译器就会访问在METADATA.jl中注册了的相应包的地址,然后从github上clone相关依赖。当然由于某些原因,这有时候会造成一些用户出现无法安装,或者下载缓慢的问题。这在第三版本的包管理器里也许会得到解决。
一个简单的Julia教程相关推荐
- (译)如何使用GameCenter制作一个简单的多人游戏教程:第一部分
免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作 ...
- Django----做一个简单网页的教程(适合初学者)
这篇文字适合刚学习Django的同学,如果比较熟的就不用看了. 以下都是讲在windows上的部署情况: 准备: 1.python3.6 2.pycharm profession(专业版) 3.安装D ...
- x64dbg破解一个简单的Demo教程
源码分析 首先需要破解的程序源码 #include <windows.h> #include <stdio.h> #include <stdlib.h> #incl ...
- 一个简单的小教程:Envi中使用光谱指数提取目标地物面积——以NDWI提取水体为例
本次实验使用Landsat8的海南省海口市影像(包括陆地和周边海域),因从GEE下载,相关预处理步骤已解决.此处为海口市的部分影像. 一.NDWI指数信息介绍 NDWI(Normalized Diff ...
- php对话框制作,js制作一个简单的对话框教程
这篇文章主要为大家详细介绍了js实现简易聊天对话框,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了js实现简易聊天对话框的具体代码,供大家参考,具体内容如下 聊天对话框 *{f ...
- C++ 高性能计算之多线程简单基础入门教程
C/C++ 高性能计算之多线程简单基础入门教程 比起别人的盲目罗列函数接口,鹦鹉学舌式的解释每一个输入参数和输出参数,一味求全而无重点,我的文章更侧重于入门知识的讲解,宁缺毋滥,只有一些最简单的入门用 ...
- Directx11教程(6) 画一个简单的三角形(2)
在上篇教程中,我们实现了在D3D11中画一个简单的三角形,但是,当我们改变窗口大小时候,三角形形状却随着窗口高宽比例改变而改变,如下图所示: 这是因为我们改变了窗口大小,但后缓冲大小在程序初始化时候, ...
- java 应用分模块_在Java 11中创建一个简单的模块化应用教程
模块化编程使人们能够将代码组织成独立的,有凝聚力的模块,这些模块可以组合在一起以实现所需的功能. 本文摘自Nick Samoylov和Mohamed Sanaulla撰写的一本名为Java 11 Co ...
- ASP.NET Aries 入门开发教程2:配置出一个简单的列表页面
前言: 朋友们都期待我稳定地工作,但创业公司若要躺下,也非意念可控. 若人生注定了风雨飘摇,那就雨中前行了. 最机开始看聊新的工作机会,欢迎推荐,创业公司也可! 同时,趁着自由时间,抓紧把这系列教程给 ...
最新文章
- 关于学习Python的一点学习总结(20->assert判断->while和for使用)
- AsyncTask应用解析
- [20180818]校内模拟赛
- 转:Android判断当前网络是否可用--示例代码
- https协议 ppt 下载卷_做PPT被版权吓得心颤颤?教你如何搞到靠谱素材
- storm 动态设置并发度
- android--------ExpandableListView的使用多级列表
- JVM:如何分析线程转储
- Windows/Linux服务器上Tomcat开启远程调试,使用IDEA本地调试
- 错过就找不到了 Java API文档 免费下载!!!
- 程序安全性之配置文件安全
- 安捷伦频谱仪的使用方法图解_安捷伦E4402B频谱仪使用说明
- 首次公开专利并且专利数量最多公司(2022.07.25-2022.7.31)
- (学习笔记)图像处理——Retinex增强
- VLAN与Trunk的配置
- 数据分析几大常见效应和定律。
- 【西北师大-2108Java】第二次作业成绩汇总
- 如何用Java打开PDF文件
- win10系统做域服务器,win10启用ad域服务器配置
- 2021-2022 ACM-ICPC Brazil Subregional Programming Contest C Creating Multiples
热门文章
- Linux ps、top、free、uname命令
- js数组转字符串 字符串转数组 去除字符串中的“ []格式
- 王者荣耀之「建造者模式」
- Centos Docker方式安装SRS服务器
- 使用C#写的一款免安装小说取名工具
- 易语言封装调用乐玩多线程插件模块
- 戴尔服务器的型号1950,PowerEdge1950的配置
- 【医学图像处理】X-ray Fluoroscopy 荧光检查
- 开仓风险计算器.xlsx(可计算:名义价值、最大资金亏损、开仓所需保证金、开仓资金杠杆、最小逐仓保证金、U本位需开张数、币本位需开张数)
- Javascript中 toFixed