柚子快報邀請碼778899分享:博客 Ruby設計-高級語法
柚子快報邀請碼778899分享:博客 Ruby設計-高級語法
一、面向?qū)ο蠡A
1.1 定義
class Point
def initialize(x, y)
@x = x
@y = y
end
end
point = Point.new(0, 1)
puts point.is_a? Point # true
? 其中 initialize 方法充當了構造器,以 @ 開頭的變量是實例變量,也就是說是 Java 中的屬性。
? 我們利用 new 方法創(chuàng)造一個變量,類似于一個工廠方法。如果往深里探究,應該是 new 方法是一個類對象方法,也就是說,Point 可以作為一個類,同時它也是 Class 這個類的一個對象,他作為對象有一個方法是 new 。這個 new 會調(diào)用實例方法(就是 java 中的非靜態(tài)方法) new ,然后完成構造。
? is_a?是一個方法,與 Java 中的 instanceof 類似。只要是這個類或者這個類的子類,都會返回 true ,與之相似的是 kind_of? 。 而如果是 instance_of? 那么就只有該類會返回 true。
1.2 實例方法
1.2.1 to_s
? 轉(zhuǎn)換成字符串的方法,如下
def to_s
"(#{@x}, #{@y})"
end
1.2.2 getter, setter
? 我們可以用常規(guī)的方法定義,沒錯,感覺 ruby 的方法名中可以出現(xiàn)各種特殊字符
# getter
def x
@x
end
def y
@y
end
# setter
def x=(value)
@x = value
end
def y=(value)
@y = value
end
? 這種方法無疑是最好的,因為可以掩蓋內(nèi)部具體的實現(xiàn)細節(jié),不過如果只是普通的 getter, setter 那么其實可以利用元編程的知識,直接用 Module 的方法。
attr_accessor :x, :y
? 所謂的“元編程”就是利用代碼創(chuàng)造代碼,這里就不詳細說了。attr_accessor 是一個 Module 的方法,Class 是 Module 的子類,可能 Point 也是 Module 的子類,所以可以使用這個方法。
1.2.3 operator
? 和 C++ 一樣,Ruby 是可以定義運算符的,而且似乎更加簡潔,跟定義方法一模一樣,這可能是由于 Ruby 的方法聲明中允許特殊字符的存在,而且單參數(shù)調(diào)用時可以不加括號導致的。我們?yōu)?Point 定義三個方法
? 定義加法:
def +(other)
Point.new(@x + other.x, @y + other.y)
end
? 定義負號,這里需要注意,有一個 -@ 的特殊寫法
# negative
def -@
Point.new(-@x, -@y);
end
? 定義數(shù)乘,這里和 C++ 一樣,是沒有辦法寫 3 * point 的,只能寫 point * 3
def *(scalar)
Point.new(@x * scalar, @y * scalar)
end
? 為了解決這個問題,我們可以定義個 coerce 方法,似乎這個方法會在 3.* 的時候使用,然后返回的值會重新調(diào)用 point.* 但是具體的原理就不清楚了。
def coerce(other)
[self, other]
end
? 定義索引訪問:
def [](index)
case index
when 0, -2 then @x
when 1, -1 then @y
when :x, "x" then @x
when :y, "y" then @y
else nil
end
end
? 這個是一個只讀數(shù)組,如果想寫這個東西,需要其他的東西。
1.2.4 iterator
? 我們可以定義迭代器方法 each
class Point
...
def each
yield @x
yield @y
end
include Enumerable
end
? 底下這個 include 很有意思,學名叫做混入。似乎 Enumerable 這個模塊里有很多基于 each 的方法,所以只要混入這個模塊,就可以擁有這一堆的迭代器方法(似乎叫做枚舉器方法更為合適)
pointA.each {|e| puts e}
puts pointA.all? {|e| e == 0}
puts Point.new(0, 0).all? {|e| e == 0}
1.2.5 equal
? 在 Ruby 中一般與 Java 相反,我們用 == 表示內(nèi)容上的相等,而用 eq? 表示同一個引用。所以我們一般需要重寫 == 號
def ==(other)
if other.is_a? Point
@x == x && @y == y
else
false
end
end
? 但是同時我們又在 Hash 結構中,使用的是 eq? 這個方法(所以前面那個約定好沒用),和 Java 一樣,如果 eq? 判斷相等了,hash 就必須判斷相等。所以只要定義了 eq? ,那么就需要定義 hash ,并且滿足前面的條件。
1.2.6 Comparable
? 只要定義了 <=> 就可以獲得一大堆比較符。
include Comparable
def <=>(other)
@x**2 + @y**2 <=> other.x**2 + other.y**2
end
Comparable 也是一個混入模塊。
1.3 類方法
? 對應的是 Java 中的靜態(tài)方法,但是實際上很不一樣。類方法在 ruby 中是類對象的單鍵方法,也就是說,類本身就是一個對象。定義單鍵方法,需要指定方法所屬的對象。如圖所示
class Point
...
def self.sum(*points) # self means the "Point", not the point
x = y = 0
points.each {|p| x += p.x; y += p.y}
Point.new(x, y)
end
end
# single-key
puts "sum = #{Point.sum(pointA, pointB, pointC)}"
1.4 類常量
? 定義在類中的常量,這個對應 Java 中的靜態(tài)常量,如下所示
class Point
...
def initialize(x, y)
end
...
ORIGIN = Point.new(0, 0)
end
puts "Origin = #{Point::ORIGIN}"
Point::UNIT_X = Point.new(1, 0)
puts "Unit x = #{Point::UNIT_X}"
? 有一個很有意思的,就是 ORIGIN 要在 initialize 之后,就很神奇,大概還有聲明先后的問題吧。
1.5 類變量
? 定義在類中的變量,靜態(tài)變量,如下所示
class Point
@@n = 0
@@totalX = 0
@@totalY = 0
...
def initialize(x, y)
@x = x
@y = y
@@n += 1
@@totalX += x
@@totalY += y
end
def self.report
puts "There are #{@@n} points"
puts "total x is #{@@totalX}"
puts "total y is #{@@totalY}"
end
end
Point.report
1.6 方法的可見性
? 默認方法一般都是 public ,除了 initialize 。當然對于全局的方法(就是函數(shù)),他是 Object 的實例私有方法。
? 同樣是三種:
private:沒法用 object.method 或者 self.method 調(diào)用,只能直接 method 使用。這只是定義,如果要解釋的話,那么就是適用于 method 這種寫法的東西,就是其他實例方法。protected:只能在
二、面向?qū)ο蟾唠A
3.1 Struct
? 利用 Struct 類可以快速創(chuàng)造出一個類,我的評價是充滿了神秘,比如說之前實現(xiàn)的 Point
OtherPoint = Struct.new(:x, :y)
class OtherPoint
def +(other)
Point.new(self.x + other.x, self.y + other.y)
end
def to_s
"(#{self.x}, #{self.y})"
end
end
? 感覺 Ruby 十分靈活,可以隨時改變類,而且可以多次改變類,如下所示
OtherPoint = Struct.new(:x, :y)
class OtherPoint
def +(other)
Point.new(self.x + other.x, self.y + other.y)
end
def to_s
"(#{self.x}, #{self.y})"
end
end
otherPointA = OtherPoint.new(4, 3)
puts otherPointA
otherPointA.x = 1
class OtherPoint
undef x=, y=
end
# otherPointA.x = 2 NoMethodError
3.2 打開
? 這個就很本質(zhì)了,就是對于這樣的語句
class SomeClass
...
end
module SomeModule
...
end
? 除了第一次有定義的意思,只有都是有“給原有的東西添磚加瓦的意思”。每次的“打開”,都意味著一種 self 指針的變換和作用域的變化。
3.3 泛化關系
? 基本上所有的類都是 Object 類的子類,Class 是 Module 類的子類,所有的類都是 Class 類的實例化,所有的模塊都是 Module 的實例化 。Kernel 是一個 Module,它混入了 Object ,所以哪里都有他,他似乎提供了基本的方法實現(xiàn)(類似于某種 stdlib)。
? 跟前面的 Struct 類似,也可以有很多神秘的語法
M = Module.new # some module called M
C = Class.new # some class called C
D = Class.new(C){include M} # some C subclass called D, which include M
3.4 include, extend
利用 include 和 extend 都可以進行 Mixin(混入操作),對于 include 就是直接混入到實例上? extend 是混入到類上?
3.5 關系
三、函數(shù)式特征
3.1 block
block 是 一小段代碼,用 {} 包裹, 用 yield 關鍵字調(diào)用。迭代器就是基于這個實現(xiàn)的。
def call_twice
yield
yield
end
call_twice {puts "Hello World"}
? yield 是可以傳參的
def call_twice
yield(1)
yield(2)
end
call_twice { |x| puts "Hello World! #{x}"}
3.2 Proc
3.3 Lambda
柚子快報邀請碼778899分享:博客 Ruby設計-高級語法
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權,聯(lián)系刪除。