学习Ruby简单语法

作者: 肠粉白粥_Hoben | 来源:发表于2019-10-18 11:34 被阅读0次

    上文讲到,要生成LinkMap,就要修改Build Setting里面的一些Flag,如果需要用脚本来控制,则需要修改到.xcodeproj文件。

    今早研究了一早的Python语法,发现都没有很好的办法去修改这个Flag,恰好看到别的文章有思路说,用Ruby来修改,试了一下,果不其然成功了,一不做二不休,干脆把Ruby的简单语法也了解一下吧!

    教程来自ruby基础教程(中文第四版)

    一. Hello World

    print("Hello World!\n")
    

    二. 数组+循环

    1. each方法

    names = ["a", "b", "c"]
    
    puts names[0]
    
    names.each do |n|
        puts n
    end
    
    /***
    输出
    a
    a
    b
    c
    ***/
    

    数组就很常见了,下面着重讲一下循环:

    在Ruby语法中,array.each do |element| end,代表着枚举一个array的元素element,循环起于do而终于end。

    2. times方法

    5.times do |n|
        puts n
    end
    
    /***
    输出
    0
    1
    2
    3
    4
    ***/
    

    3. for方法

    sum = 0
    
    for i in 1..5
        sum = sum + i
        puts sum
    end
    
    /***
    输出
    1
    3
    6
    10
    15
    ***/
    

    4. while方法

    sum = 0
    
    i = 1
    
    while i <= 5
        sum = sum + i
        i += 1
        puts sum
    end
    
    /***
    输出
    1
    3
    6
    10
    15
    ***/
    

    5. break, next

    array = ["a", "b", "c", "d", "e"]
    
    array.each do |element|
        break if element == "c"
        puts element
    end
    
    /***
    输出
    a
    b
    ***/
    
    array = ["a", "b", "c", "d", "e"]
    
    array.each do |element|
        next if element == "c"
        puts element
    end
    
    /***
    输出
    a
    b
    d
    e
    ***/
    

    三. 参数

    命令ruby file.rb arg1 arg2....中,可以通过ARGV来读取到该命令的参数,默认读取到的为字符,也可以将其转化为数字,从而进行运算操作。

    str0 = ARGV[0]
    str1 = ARGV[1]
    
    puts "#{str0} + #{str1} = #{str0 + str1}"
    
    /***
    输出
    1 + 2 = 12
    ***/
    
    num0 = ARGV[0].to_i
    num1 = ARGV[1].to_i
    
    puts "#{num0} + #{num1} = #{num0 + num1}"
    
    /***
    输出
    1 + 2 = 3
    ***/
    

    四. 文件IO

    1. 读取整个文件

    filename = ARGV[0]
    file = File.open(filename)
    text = file.read
    print text + "\n"
    file.close
    

    2. 逐行读取

    如果只需要读取一个大文件里面的前几行,逐行读取会比较节省性能

    filename = ARGV[0]
    file = File.open(filename)
    file.each_line do |line|
        print line
    end
    print "\n"
    file.close
    

    3. 带正则表达式的读取

    如果需要匹配一个文件里面的一些字符,则可以带上正则表达式

    pattern = Regexp.new(ARGV[0])
    
    filename = ARGV[1]
    file = File.open(filename)
    file.each_line do |line|
        print line if pattern =~ line
    end
    print "\n"
    file.close
    

    下面这行命令,代表过滤含tbd字符串的文件,并打印出来

    ruby LearnRuby.rb tbd BaseLinkMapResult.txt 
    

    五. 引用库

    通过require方法来引用库。

    // LearnRuby.rb
    def hello
        puts "Hello World"
    end
    
    // PrintRuby.rb
    
    require './LearnRuby.rb'
    
    hello()
    
    // command
    ruby PrintRuby.rb
    

    六. 方法、变量

    1. 方法

    def hello
        puts "Hello World"
    end
    
    hello()
    

    2. 变量

    局部变量:x,全局变量:$x

    // LearnRuby.rb
    $x = 1
    x = 1
    
    // PrintRuby.rb
    $x = 0
    x = 0
    
    require './LearnRuby.rb'
    
    puts $x
    puts x
    
    // result
    1
    0
    

    3. 常量

    常量用全大写字母声明,与变量相似,但是修改常量会报警告。

    TEST = 1
    TEST = 2
    
    puts TEST
    
    // result
    PrintRuby.rb:2: warning: already initialized constant TEST
    PrintRuby.rb:1: warning: previous definition of TEST was here
    2
    

    4. 多重赋值

    支持对应赋值语法

    a, b, c = 1, 2
    
    p [a, b, c]
    
    // result
    [1, 2, nil]
    

    利用这个可以做出置换变量

    a, b = 1, 2
    a, b = b, a
    p [a, b]
    
    // result
    [2,1]
    

    七. 类

    1. 定义

    class Person
        attr_accessor :name
    
        def initialize(myname = "Default")
            @name = myname
        end
    
        def greet
            puts "Nice to meet u, #{self.name}"
        end
    end
    
    person = Person.new("Hoben")
    
    person.greet()
    
    // result
    Nice to meet u, Hoben
    

    attr_accessor代表着该类自动生成了getter和setter方法,initialize是初始化方法,里面可以放置参数,调用的时候,是object = Class.new()

    如果需要自定义getter和setter方法,则需要这样来定义:

    class Person
        # attr_accessor :name
    
        def name    # getter
            puts "It's Getter"
            @name
        end
    
        def name=(value)    # setter
            puts "It's Setter"
            @name = value
        end
    
        def initialize(myname = "Default")
            @name = myname
        end
    
        def greet(value)
            puts "Nice to meet u, #{value}"
        end
    end
    
    person = Person.new()
    
    person.name = "NewName"
    
    person.greet(person.name)
    
    // result
    It's Setter
    It's Getter
    Nice to meet u, NewName
    

    注意:在自身类中self.name会调用getter,而@name则不会调用getter方法。(这个和OC很像)

    2. public/private/protected

    class Person
        def PublicMethod
            puts "Public"
        end
    
        public:PublicMethod
    
        def PrivateMethod
            puts "Private"
        end
    
        private:PrivateMethod
    end
    
    person = Person.new()
    
    person.PublicMethod()
    
    // 这里会报错
    person.PrivateMethod()
    

    其实和C++差不多,不多说了

    3. 继承与扩展

    继承用Son < Father来表示,用super来表示继承父类方法。

    class Father
        def PublicMethod
            puts "Public"
        end
    
        public:PublicMethod
    
        def PrivateMethod
            puts "Private"
        end
    
        private:PrivateMethod
    
        def ProtectedMethod
            puts "Father Protected" 
        end
    
        protected:ProtectedMethod
    end
    
    class Son < Father
        def ProtectedMethod
            super()
            puts "Son Protected"
        end
    
        public:ProtectedMethod
    end
    
    son = Son.new()
    
    son.ProtectedMethod()
    
    // result
    Father Protected
    Son Protected
    

    当然,也可以在原类的基础上去添加方法,使用扩展。

    class String
        def expandMethod
            puts "It's Expand Method"
        end
    end
    
    s = String.new()
    s.expandMethod()
    

    4. 模块

    模块Module和类Class相似,但又有点不同,是Ruby里面特有的用法,不同之处在于:

    • 模块不能拥有实例

    • 模块不能被继承

    通过命名模块,我们可以在引用时省略模块名,直接一个include搞定,如:

    // 下面两个一样
    p Math::PI
    
    include Math
    p PI
    

    如果有两个类,他们有共同的方法,但是又不希望将它们归为同一个Class的话,可以考虑采用模块:

    module Common
        def commonMethod
            puts "Common"
        end
    
        Version = "1.0"
    end
    
    class SubClass1
        include Common
    
        def firstMethod
            puts "First"
        end
    end
    
    class SubClass2
        include Common
    
        def secondMethod
            puts "Second"
        end
    end
    
    first = SubClass1.new
    second = SubClass2.new
    
    first.commonMethod
    first.firstMethod
    
    second.commonMethod
    second.secondMethod
    
    include Common
    puts Version
    
    // result
    Common
    First
    Common
    Second
    1.0
    

    Extend方法可以使得单例类包含模块,并把模块的功能扩展到对象中。

    module Edition
        def edition(n)
            "#{self} No.#{n}"
        end
    end
    
    str = "This is module:"
    
    str.extend(Edition)
    
    p str.edition(4)
    
    // result
    "This is module: No.4"
    

    在上面的例子中,可以看到str扩展了一个Edition的module,在edition方法中,他提前设定了"xxx No.x"的字符串,当str扩展了这个module后,就可以先把自身打印出去,再套入输入的结果。

    八. 逻辑运算

    1. 比较有特色的逻辑

    和C++的逻辑运算大同小异,讲一些比较有特色的:

    // 当var不为空name = var,当var为空name = Ruby
    name = var || "Ruby"
    
    // 当ary为空item为nil,当ary不为空,item为ary[0]
    item = ary && ary[0]
    
    // [1, 10]
    1..10
    
    // [1, 10)
    1...10
    

    2. 重载

    二元运算符:可以将运算符名作为方法名,从而重定义运算符。

    class Point
        attr_accessor :x, :y
    
        def initialize(x=0, y=0)
            @x, @y = x, y
        end
    
        def position
            "(#{x}, #{y})"
        end
    
        def +(other)    #加法运算
            self.class.new(x + other.x, y + other.y)
        end
    
        def -(other)
            self.class.new(x - other.x, y - other.y)
        end
    end
    
    p1 = Point.new(1, 1)
    p2 = Point.new(2, 2)
    
    p (p1 - p2).position
    p (p1 + p2).position
    
    // result
    "(-1, -1)"
    "(3, 3)"
    

    当然,一元运算符也可以重载

    class Point
        attr_accessor :x, :y
    
        def initialize(x=0, y=0)
            @x, @y = x, y
        end
    
        def position
            "(#{x}, #{y})"
        end
    
        def +@
            dup     #返回自己的副本
        end
    
        def -@
            self.class.new(-x, -y)
        end
    
        def ~@
            self.class.new(y, x)
        end
    end
    
    p1 = Point.new(1, 2)
    p (+p1).position
    p (-p1).position
    p (~p1).position
    
    // result
    "(1, 2)"
    "(-1, -2)"
    "(2, 1)"
    

    甚至下标也可以重载

    class Point
        attr_accessor :x, :y
    
        def initialize(x=0, y=0)
            @x, @y = x, y
        end
    
        def position
            "(#{x}, #{y})"
        end
    
        def [](index)
            return x if index == 0
            return y if index == 1
            return "Out of Range"
        end
    
        def []=(index, value)
            self.x = value if index == 0
            self.y = value if index == 1
            return "Out of Range"
        end
    end
    
    p1 = Point.new(1, 2)
    
    p1[0] = 3
    p1[1] = 4
    p2 = Point.new(p1[0], p1[1])
    p p2.position
    
    // result
    "(1, 2)"
    

    九. 异常处理

    begin ~ rescue ~ ensure ~ end来描述,需要抛出异常时,则调用raise方法,
    类似于 try ~ catch ~ finally,调用throw抛出异常

    begin
     有可能发生异常的处理
        raise...
    rescue => 变量
     发生异常后的处理
    ensure
     不管是否发生异常都希望执行的处理
    end
    

    运用到打开文件中,如果打开异常也需要关闭文件,则可以用该方法来处理。

    file = File.open("sample.txt")
    begin
        file.each do |file|
            file.each_line do |line|
                puts line
            end
        end
    rescue Exception => e
        puts e.exception
    ensure
        file.close
    end
    

    十. 块

    块,即代码块,会在循环、替换算法中用到,也可以作为参数传入另一个块里面,和iOS的block有异曲同工之妙。

    1. 替换算法

    Array提供sort方法,用于从小到大去排序数组,但是如果我们要写cmp的话,就要自己去定义了。

    array = ["d", "cc", "bbb", "aaaa"]
    
    sorted = array.sort
    sortedByLength = array.sort { |a, b|  a.length <=> b.length}
    
    p sorted, sortedByLength
    
    // result
    ["aaaa", "bbb", "cc", "d"]
    ["d", "cc", "bbb", "aaaa"]
    

    根据上面的例子,可以看到,sort函数是根据字母的大小来判断的,而加入了cmp,则可以根据数组长度来判断。

    其中,<=>表示

    2. 传递块

    def total(from, to)
        result = 0
        from.upto(to) do |num|
            if block_given?
                result += yield(num)
            else
                result += num
            end
        end
        return result
    end
    
    p total(1, 5)
    p total(1, 5){|num| num ** 2}
    
    // result
    15
    55
    

    yield代表取块里面的值,block_given可以用于判断是否有传入块,from.upto(to)代表遍历from..to,也可以用(from..to).each来代替,可以看到,当传入块的时候,计算的结果为1^2+2^2+...+5^2

    yield可以接收若干个参数,并使用这些参数。

    def block_test
        yield()         # 0个块变量
        yield(1)        # 1个块变量
        yield(1, 2, 3)  # 2个块变量
    end
    
    p '通过|a|接收变量'
    
    block_test do |a|
        p [a]
    end
    
    p '通过|a, b, c|接收变量'
    
    block_test do |a, b, c|
        p [a, b, c]
    end
    
    // result
    "通过|a|接收变量"
    [nil]
    [1]
    [1]
    "通过|a, b, c|接收变量"
    [nil, nil, nil]
    [1, nil, nil]
    [1, 2, 3]
    

    相关文章

      网友评论

        本文标题:学习Ruby简单语法

        本文链接:https://www.haomeiwen.com/subject/swzmmctx.html