工作需要,需要使用静态语言crystal,但crystal的资料很少,语法接近ruby,网上说crystal是一帮ruby的爱好者搞起来的语言,废话不多,进入主题。
学习视频:https://www.bilibili.com/video/BV1QW411F7rh?p=1
ruby 通过 -v 查看版本 Python -V
[sidian@VM_0_17_centos ruby_study]$ ruby -v ruby 2.0.0p648 (2015-12-16) [x86_64-linux] [sidian@VM_0_17_centos ruby_study]$ python3 -V Python 3.7.4 [sidian@VM_0_17_centos ruby_study]$
通过irb进入交互界面. Python 进行命令行python就可以,或者安装了ipython命令行ipython进入交互模式
通过puts 屏幕终端输出信息 py通过print输出屏幕终端
[sidian@VM_0_17_centos ruby_study]$ irb irb(main):001:0> puts "hello world" hello world => nil irb(main):002:0> exit [sidian@VM_0_17_centos ruby_study]$ python3 Python 3.7.4 (default, Oct 28 2019, 00:18:00) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> print("hello,owlrd") hello,owlrd >>>
ruby构建函数基本与Python差不多
[sidian@VM_0_17_centos ruby_study]$ cat hello.rb #!/usr/bin/ruby -w def sayhello(name="sidian") puts "hello #{name}." end #sayhello("sidian") sayhello("wudian")
总体来说就多了一个end,而且当默认没有参数的时候,可以省略小括号。
接下来直接定义类,跟Python非常像
[sidian@VM_0_17_centos ruby_study]$ cat class_player.rb class Player def initialize(name = "sidian") @name = name end def show() puts "play: #{@name}" end end sidian = Player.new("wudian") sidian.show() world = Player.new("world") world.show()
从定义可以看出,实例化需要使用类属性new()执行,调用该类属性。通过new小括号里面进行实例化参数的传递
类内部实例的属性定义,通过@号实现,这个跟Python中的self.的形式进行实例属性复制差不多。
当调用类属性new以后,首先自动触发执行类方法initialize函数,进行实例对象的初始化并返回。相对与Python的__init__初始化方法弱爆了。
格式话输出的还是通过#{}的方式输出。
ruby的instance_methods, respond_to?, send的三个命令参数,对应Python的dir或vars,第二个就是hasattr,第三个就是getattr()以后执行.
首先展示instance_methods这是一个类属性,实例不具有,通过类名可以调用该方法,内部可以传参数(true或false)【暂时没有找到查看所有实例属性的函数或者方法】
class Game def initialize(title = "学习", price = "无价") @title = title @price = price # 实例属性复制 end def show puts "标题是:#{@title}" puts "价格是:#{@price}" end def show2() end def show3 end end puts Game.instance_methods(false) g = Game.new() puts g puts Game.instance_methods(true) puts g.instance_methods(false) ~
结果
ruby class_game show show2 show3 #<Game:0x00000000f9ac90> show show2 show3 nil? === =~ !~ eql? hash <=> class singleton_class clone dup taint tainted? untaint untrust untrusted? trust freeze frozen? to_s inspect methods singleton_methods protected_methods private_methods public_methods instance_variables instance_variable_get instance_variable_set instance_variable_defined? remove_instance_variable instance_of? kind_of? is_a? tap send public_send respond_to? extend display method public_method define_singleton_method object_id to_enum enum_for == equal? ! != instance_eval instance_exec __send__ __id__ class_game:20:in `<main>': undefined method `instance_methods' for #<Game:0x00000000f9ac90 @title="学习", @price="无价"> (NoMethodError) [sidian@VM_0_17_centos ruby_study]$
通过结果可以看出来instance_methods类方法,实例使用会报错,如果传入flase返回的是定义类的时候传入的属性(函数),
如果传入true或者不传入,那返回的是类所有的属性,一些属性应该是类创建的时候,继承与python中的object类似。
16 puts Game.instance_methods(false) 17 g = Game.new() 18 puts g 19 if g.respond_to?("shw2") # 这个就跟Python中的hasattr就一样的,只不过一个是函数,一个是方法 20 puts "show2 is in" 21 end 22 23 # puts Game.instance_methods() 24 # puts g.instance_methods(false)
respont_to?返回一个实例对象是否存在一个继承与类的属性???应该是,至少实例的属性不行,这个跟hasattr有点区别。
我刚测试,只有show,show1,show2返回的是真,实例的属性resopt_to并不会读取到。根据我的测试返回的就是instance_methods()类方法调用以后返回值里面的值,只要
在该值范围的内的都为真。
send就跟getattr()()这个有点像了,就是通过字符串的形式给实例传递方法的名字,并运行该方法。ruby的函数,没有默认参数的情况下,不用()也会执行
17 g = Game.new() 18 puts g 19 if g.respond_to?("send") # "send"在instance_methods的内容中,所以会执行g.send 20 puts g.send("show") # 传入类中定义的函数 21 end 22 23 # puts Game.instance_methods() 24 # puts g.instance_methods(false)
结果
[sidian@VM_0_17_centos ruby_study]$ ruby class_game show show2 show3 #<Game:0x00000001446c08> 标题是:学习 价格是:无价
私有属性能够被外部需要在类属性中定义一个attr_accessor :price, :name,:属性名字
这样定义以后在instance_methons能够读取该属性,一读取还是两个一个是属性名称,一个是属性名称加=号
Last login: Sun May 10 22:01:34 on ttys004 You have mail. The default interactive shell is now zsh. To update your account to use zsh, please run `chsh -s /bin/zsh`. For more details, please visit https://support.apple.com/kb/HT208050. shijianongdeMBP:~ shijianzhong$ ssh tx Last login: Sun May 10 21:59:49 2020 from 115.194.189.151 [sidian@VM_0_17_centos ~]$ ls all.sql c_study db1_out_txt exec_new3.sh mysql.log newfile test crystal_centos.tar c.tar dump.rdb log2.txt new3_report ruby_study test.txt [sidian@VM_0_17_centos ~]$ cd ruby_study/ [sidian@VM_0_17_centos ruby_study]$ ls ary.rb begin_end.rb begin.rb hello.rb here.rb hsh.rb 方法 [sidian@VM_0_17_centos ruby_study]$ ruby hello.rb hello.rb:8:in `<main>': undefined local variable or method `syahello' for main:Object (NameError) [sidian@VM_0_17_centos ruby_study]$ ruby hello.rb hello sidian. [sidian@VM_0_17_centos ruby_study]$ ruby hello.rb hello wudian. [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb class_player.rb:6:in `show': undefined method `purs' for #<Player:0x000000013b8160> (NoMethodError) from class_player.rb:12:in `<main>' [sidian@VM_0_17_centos ruby_study]$ ruby hello.rb hello wudian. [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb play: [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb class_player.rb:11:in `initialize': wrong number of arguments (1 for 0) (ArgumentError) from class_player.rb:11:in `new' from class_player.rb:11:in `<main>' [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb class_player.rb:11:in `initialize': wrong number of arguments (1 for 0) (ArgumentError) from class_player.rb:11:in `new' from class_player.rb:11:in `<main>' [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb play: [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb play: sidian [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb play: wudian [sidian@VM_0_17_centos ruby_study]$ ruby class_player.rb play: wudian play: world [sidian@VM_0_17_centos ruby_study]$ ls ary.rb begin_end.rb begin.rb class_player.rb hello.rb here.rb hsh.rb 方法 [sidian@VM_0_17_centos ruby_study]$ cat hello.rb #!/usr/bin/ruby -w def sayhello(name="sidian") puts "hello #{name}." end #sayhello("sidian") sayhello("wudian") [sidian@VM_0_17_centos ruby_study]$ cat class_player.rb class Player def initialize(name = "sidian") @name = name end def show() puts "play: #{@name}" end end sidian = Player.new("wudian") sidian.show() world = Player.new("world") world.show() [sidian@VM_0_17_centos ruby_study]$ packet_write_wait: Connection to 212.64.47.160 port 22: Broken pipe shijianongdeMBP:~ shijianzhong$ ssh tx Last login: Sun May 10 23:10:31 2020 from 115.194.189.151 [sidian@VM_0_17_centos ~]$ ls all.sql c_study db1_out_txt exec_new3.sh mysql.log newfile test crystal_centos.tar c.tar dump.rdb log2.txt new3_report ruby_study test.txt [sidian@VM_0_17_centos ~]$ cd ruby_study/ [sidian@VM_0_17_centos ruby_study]$ cal 五月 2020 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [sidian@VM_0_17_centos ruby_study]$ pqd -bash: pqd: 未找到命令 [sidian@VM_0_17_centos ruby_study]$ pwd /home/sidian/ruby_study [sidian@VM_0_17_centos ruby_study]$ ls ary.rb begin_end.rb begin.rb class_game class_player.rb hello.rb here.rb hsh.rb 方法 [sidian@VM_0_17_centos ruby_study]$ cat class_player.rb > class_player2.rb [sidian@VM_0_17_centos ruby_study]$ vim class_player2.rb class Player attr_accessor :price, :name # 只有这里定义了,实例才能在外面读取该属性。 def initialize(name = "sidian", price = 150) @name = name @price = price end def show() puts "play: #{@name}" puts "price: #{@price}" end end sidian = Player.new("wudian") sidian.show() world = Player.new("world") world.show() puts world.respond_to?("price=").to_s world.price = 500 world.name= "白痴" world.show() puts " " puts world.name puts Player.instance_methods(false) ~ ~ ~ "class_player2.rb" 24L, 474C 已写入 2,25 全部
[sidian@VM_0_17_centos ruby_study]$ ruby class_player2.rb play: wudian price: 150 play: world price: 150 true play: 白痴 price: 500 白痴 price price= name name= show
列表的操作 each do, each_with_index
game_list = ["实", "建忠", "牛逼"] game_list.each do |li| # 列表具有each属性 puts "out_put#{li}" end game_list.each_with_index do |li,i| puts "my index#{i},content#{li}" end puts game_list.respond_to?("each").to_s # 可以通过respond_to?返回的值,判断一个对象是否具有该属性判断是否为列表 puts game_list.join("中间") # 该方法跟Python一样
out_put实 out_put建忠 out_put牛逼 my index0,content实 my index1,content建忠 my index2,content牛逼 true 实中间建忠中间牛逼
备注的使用
一行备注 跟Python 一样 #
多行备注 =begin ... =end 跟Python的""""""差不多,三引号
之后全部备注 __END__
操作符号
基本与Python一样, 除了逻辑操作符 &&,||,!等于Python中and or not
irb(main):016:0> ! nil => true irb(main):017:0> ! false => true irb(main):018:0> ! [] => false irb(main):020:0> ! 0 => false irb(main):021:0>
ruby 中只有false 与 nil才为假
三项运算式
irb(main):004:0> point => 30 irb(main):005:0> puts point >= 30 ?"mvp": "一般" mvp => nil irb(main):006:0> puts point > 30 ?"mvp": "一般" 一般 => nil irb(main):007:0>
标准语法 条件 ? 真的返回:假的返回
Python中的用法
In [1]: 3 if 3>1 else 'lala' Out[1]: 3
起始从逻辑来看,还是ruby的更加容易理解,但Python的我肯定不会说他差。
字符串的操作 + << *
irb(main):007:0> a = "hello" => "hello" irb(main):008:0> b = "sidian" => "sidian" irb(main):009:0> a+b => "hellosidian" irb(main):010:0> a << b => "hellosidian" irb(main):012:0> a *5 => "hellosidianhellosidianhellosidianhellosidianhellosidian" irb(main):013:0> a => "hellosidian" irb(main):014:0>
从操作中看出+两个对象相加, <<相当于Python中的a = a+b, *跟Python的操作基本一样
单引号与双引号的区别
irb(main):021:0> " " => " " irb(main):022:0> p1 = "我号" => "我号" irb(main):023:0> puts p1 我号 => nil irb(main):024:0> "aa bb" => "aa bb" irb(main):025:0> p2 = 'aa bb' => "aa\nbb" irb(main):026:0> puts p2 aa bb => nil irb(main):027:0> myp = "#{1+2}" => "3" irb(main):028:0> myp = '#{1+2}' => "#{1+2}" irb(main):029:0> puts myp #{1+2} => nil irb(main):030:0>
从运行可以看出单引号好比python中的r不进行任何转义输出,双引号#{}输出,好比Python中的format格式化的f {}格式化输出
哈希变量操作,也就是Python中字典的操作,新建
irb(main):033:0> mvp = {"sidian" => 'niubi',"wudiain"=>5} => {"sidian"=>"niubi", "wudiain"=>5} irb(main):034:0> myp => "#{1+2}" irb(main):035:0> mvp => {"sidian"=>"niubi", "wudiain"=>5} irb(main):036:0> mvp["wudian"] => nil irb(main):037:0> mvp["sidian"] => "niubi" irb(main):038:0> mvp["sidiain"] => nil irb(main):039:0> mvp["wudiain"] => 5 irb(main):041:0> player = {name: 'sidian',age:18} => {:name=>"sidian", :age=>18} irb(main):042:0> player[:name] => "sidian" irb(main):043:0> player[:nam] => nil irb(main):044:0>
有两种创建方式,一种是通过=>的方式,取value通过[key],第二种是跟Python差不多的新建方式
但取值的时候通过[:value]的方式,这里发现一个有意思的玩意,就是如果取不到值返回的是nil,也就是跟false差不多
数据的转换,to_i,to_s,to_f相对与Python中的int,str,float
irb(main):047:0> a = 1.23 => 1.23 irb(main):048:0> a.to_i => 1 irb(main):049:0> a.to_f => 1.23 irb(main):050:0> a = "实践中" => "实践中" irb(main):051:0> b = irb(main):052:0* irb(main):053:0* b = "123" => "123" irb(main):054:0> b.to_i + 456 => 579 irb(main):055:0> c = "1.55" => "1.55" irb(main):056:0> c.to_i => 1 irb(main):057:0> c = 1.55 => 1.55 irb(main):058:0> c.to_i => 1 irb(main):059:0>
可以啊,to_i直接把字符串的float转换成整形,比Python牛逼么
class 再入门
class Player def initialize(name = "sidian") @name = name end def show() puts "play: #{@name}" end def self.toStr # 静态方法不能被实例调用 puts "my method is static" end end sidian = Player.new("wudian") sidian.show() world = Player.new("world") world.show() Player.toStr
这个有个意义的东西,就是定义静态方法self.method,静态方法只能通过类名调用,无法通过实例调用。
类的继承
通过< 实现 儿子类名 < 父亲类名
没啥套路,不写了,直接所有的父类属性全部继承
模块的定义跟Python完全不一样了,需要通过命令 module来实现一个模块
调用模块的属性通过::,调用模块定义的静态方法可以通过::或者.,另外模块定义的函数可以传递给类
module BaseFunc Version = "0.0.1" def v return Version end def add(a, b) # 非静态方法不属于模块方法 return a+b end def self.showVersiona # 静态方法 return Version end module_function :v # 定义为静态方法 end puts BaseFunc::Version # 模块中的属性通过::读取 #puts BaseDunc.Version # .不能读取 class BaseClass include BaseFunc # 类中包含读取BaseFunc模块 end puts BaseClass::Version b = BaseClass.new puts b.add(1,2) ~
代码做了一些注释了,很有意思,模块中定义的方法,如果不定义称为静态方法,模块尽然不能直接调用,一定要称为静态方法才可以调用。
静态方法可以通过module_function :函数命 或者 self.函数名的方式编程静态方法
当一个类通过include包含了这个模块,可以通过::读取模块的属性,但不能调用模块的静态方法,但类的实例可以调用模块内定义的普通函数,有意思的家伙。
条件控制文
if elsif else unless else case when else
p = 15 if p >=30 puts "3500万一年" elsif p >= 20 puts "20一年" else puts "else这里来了" end unless p < 10 # 这个是不成立才触发 puts "unless 触发" else puts "unldess未触发" end week_day = "3".to_i case week_day # 传入一个对象 when 0,7 # 比较这个对象 puts "星期天" when 1,2 puts "这个是星期1或者2" when 3 puts "这个是星期#{week_day}" else # 都没有的话,传入到这里 puts "这个输入我没搞错" end
相比Python,这个语法确实丰富多了,有三个。
循环处理
gamelist = ["one", "two", "three"] for g in gamelist do puts g end for i in 1..5 do puts i end for i in 1...5 do puts i end n = 1 while n < 5 do puts "while #{n}" n += 1 end puts n until n == 2 do # 这个也很有意思,这个也是不成立才执行,日常开发用的少 puts "until #{n}" n -= 1 end ~
与Python相比多了一个do,还有一个until,另外的理解都差不多,还有那个可恶的end我经常忘记了。
特殊循环
g_list = ["one", "two", "three"] g_list.each {|game| puts game} g_list.each do |game| puts game end g_list.each_with_index do |g, i| puts g + (i+1).to_s end g_list.each_with_index{ |g, i| puts g, i } 5.times do |i| # 重复执行 puts "time #{i}" end 1.step(10, 3) do |i| # 起始数字step,参数结束数字,步进 puts "step #{i}" end
array有each的属性,后面通过do 或者{}迭代读取参数或者执行脚本
5.times do |i| 就是执行几次的意思,i自动会上+
x.step(a,b) do |i| x是起始数字,a是结束数字,b是步进
upto downto操作循环
[sidian@VM_0_17_centos ruby_study]$ vim each.rb [sidian@VM_0_17_centos ruby_study]$ vim upto_downto.rb 2.upto(5) do |i| puts "upto#{i}" end 5.downto(2) do |i| puts "down#{i}" end ~
[sidian@VM_0_17_centos ruby_study]$ ruby upto_downto.rb upto2 upto3 upto4 upto5 down5 down4 down3 down2
这个step,upto,downto应该都是同一个批次的命令,这里的取值都是包含最后的取值的,也就是最后那个数字能够读取到的。
错误捕捉,begin rescue else ensure 对于错误的捕捉
begin # 相当于Python中的try puts "逻辑开始执行" 10 / 0 rescue => e # 相当于Python中的except Except as e puts "错误接收到了" puts e else puts "正常处理开始了" # 这个Python中也有,是在用的很少 ensure puts "这个我肯定要执行的" # 相当于Python中的finally end
[sidian@VM_0_17_centos ruby_study]$ ruby begin_rescue.rb 逻辑开始执行 错误接收到了 divided by 0 这个我肯定要执行的
最后写一个获取对象的方法.methods