標籤:

ruby語言有什麼樣的美學特點?


補充點這個問題下還沒回答提到的:

Ruby內建的語法和語言功能有不少地方閃耀著「一致性」的特徵,同時還具有高度的靈活性,讓我很是喜歡。

例如說,Ruby里有些看起來很花哨的DSL,其核心都是使用了三種語言功能:

  • 方法調用:代碼看到一個小寫的名字就可以知道它要麼是局部變數要麼是方法調用;然而如果沒在局部作用域里看到這個「變數」的話就可以知道它肯定是方法調用了。Ruby可以通過方法調用做很多文章,無論是method_missing還是instance_eval等,從用戶的一側看都是方法調用(或者說message send…我沒那麼原教旨不介意用哪種說法)
  • 開放的類:這個不用多說了
  • block與non-local control flow:有了這倆功能的組合,就可以頗方便的在DSL里自定義控制流結構,例如自定義循環控制流——Ruby核心庫的Kernel#loop就可以用Ruby聲明,參考Rubinius的源碼:rubinius/kernel.rb at master · rubinius/rubinius · GitHub

以前我很喜歡拿到Ruby代碼後把它parse出AST來看看,確認一下我理解的結構是否跟實際的AST吻合。後來發現大部分我有疑問的地方其實都是方法調用,心裡就踏實了。後來就不那麼需要總是去看AST了。

然後還有一點我很喜歡的就是「Principle of Least Surprise」——用戶覺得什麼是自然的,那就可以怎麼寫。

例如說,在Ruby里,Array有#length和#size方法,而且它們是同一個方法——Array#size是Array#length的別名。這樣我寫代碼就不用糾結到底要用哪個了。

而在Java里,數組有.length屬性,ArrayList卻沒有length()方法而只有size()方法,我經常寫Java代碼還是會偶爾混亂一下…

同樣,Ruby的Enumerable#reduce和Enumerable#inject也是同一個實現的兩個名字。以前我剛用Ruby的時候只有#inject覺得怪怪的,但反正知道是reduce/fold的意思就這麼用吧;後來Ruby 1.8.7新加了#reduce這個名字之後就感覺順多了。


Ruby是披著VB和Perl語法偽裝的Smalltalk。這層偽裝使得它可以和這個已經過氣的偉大語言保持恰當的距離,並且不那麼容易嚇壞初學者。從這個角度講,似乎不宜單獨評論Ruby的美學特點。

例如,上面提到的一些特色其實不是來自Matz,而是來自Alan Kay。

open class:因為Smalltalk不區分開發和運行環境,open class是必須而非特色 -- 代碼就是一個方法一個方法添加出來的。

block:這是Smalltalk的基石。因為這個語言源於Alan Kay的一個思想實驗:能不能創造一個比LISP更簡單的語言,其解釋器的核心能在一頁紙上寫下?因為block使得控制結構可以由用戶代碼實現,Smalltalk才會出現。

類庫:Ruby的核心類庫與Smalltalk非常相像。


瀉藥。

第一點是複雜。

其實如果不是Ruby這麼複雜的話並不會吸引我去愛上它。

當然因為它複雜到可以做各種事情,反過來設計出來給終端用戶用的時候就能做一套簡單的DSL了。

比如有些答案提到的Sinatra,很好用嘛。簡潔方便,表達能力超強。

但是你想去實現或者去擴展他,就知道我說的複雜在哪兒了。

不過Ruby的複雜不是不著邊際,而是傾向於用利用自身複雜的特性去簡化複雜的邏輯。Matz設計的時候就是要給所有人都可以玩的語言,所以即便你不去了解這麼複雜的Ruby,希望能夠開心地玩。

第二點就是整潔。

不是**簡潔**是**整潔**。

比如把?和!作為notation,來表示是一個predicate或者是有side-effect;比如Enumerable配合block流暢的使用方法;比如convention over configuration;比如媲美Perl的正則表達式。

第三點就是,融合得完美,可以用多種風格編程。

這裡的融合指的是LISP和Smalltalk。除了沒有宏之外,能有的都有了,而且一點都不顯得意外。(當然你還可以用黑魔法來模擬宏。

在動態語言裡面,Ruby的這套對象模型的應該是業界標杆了。

暫時只想到這些。

以上。


菊花與菜刀的暴力美學

(傳不了圖腦補表情吧 :hhh)


寫 Ruby 很多年... 甚為喜歡...

美這個東西有點主觀, 但是還是試著回答一下吧!

我覺得 Ruby 的美主要體現在兩點:

1. 簡潔

Ruby 是一門非常簡潔的語言. 怎麼體現它的簡潔呢? 例子其實可以舉很多, 我這裡就舉一個最簡單的例子吧:

print "Hello World!"

這就是一個 hello world 程序, 它已經達到"最簡". 也就是說你再拿掉這行代碼的任何一個字元都是不合理的, 它已經是最簡.

複雜是各有各的複雜, 而至簡通常都是歸於統一的.

所以這一行代碼實際上用 Python 和 Ruby 都可以執行.

所以換句話說 Python 也是一門很簡潔的語言. :)

2. 一致

一致性在 Ruby 中也有很多的體現, 而這裡我著重說一點就是: In Ruby, everything is an object.

這裡一點怎麼體現呢?

如下代碼:

50.to_s #=&> "50"
50.is_a? Object #=&> true

在 Ruby里沒有所謂的基本類型, 所有東西都是對象. 這裡的 50 在 Ruby 里也是一個對象, 所以你可以調用它的 to_s 方法.

再舉一個例子:

class Boy
def play_game
puts "I"m loling!!"
end
end

boy = Boy.new

boy.class #=&> Boy
Boy.class #=&> Class

boy.instance_of? Boy #=&> true
Boy.instance_of? Class #=&> true

boy.is_a? Object #=&> true
Boy.is_a? Object #=&> true
Class.is_a? Object #=&> true

上面一個例子說明一個問題, Boy 類實際上也是一個對象, Boy 類實際上是 Class 的實例.

而 class 關鍵字有點 shortcut 的味道. 本質上來講, Ruby 中的類也是對象.

所以 Everything is an object. 體現了 Ruby 的一致性, 也算是我覺得它美的一個方面.


想起之前看到的兩張圖:

(圖片來源:http://www.slideshare.net/abreslav/trade-offs-22989326)

「Simply Universal」的語言追求語言本身的概念的簡潔,代表是 C, Lua, Lisp, Java?, Go? 等,極致是 Lisp ,一個 lambda 打遍天下。

「Full of Shortcuts」的語言本身比較複雜,但可以讓你寫出來的程序更簡潔,代表是 Ruby, Scala, C++?? 。

我個人以前是 C / Lua 陣營的,學習了 Scala 之後被帶歪了,現在已投靠 Ruby 啦。我比較贊同松本行弘先生在訪談(圖靈社區 : 閱讀 : 松本行弘:代碼的未來(圖靈訪談))時說的:

我覺得這也許是因為Lisp對於大多數程序員來說不具備那麼大的魅力,也就是說,作為一種「擁有最小核心」的語言,或者從某種意義上說是一種很「美麗」的語言,和程序員們所期望的語言之間,存在著一定的差距。如果一兩年的時間裡,Lisp的魅力沒有被大家所接受,那還可以理解,但已經過了50年還沒有被廣泛接受的話,是不是它在本質上就不太符合大家的期望呢?「對人類來說好用的語言」和「擁有最小核心的語言」之間的這個差距可能是很大的,我覺得可能將來100年也沒辦法消除。

「讓你寫出來的程序更簡潔」即是第二類語言的簡潔,也是 Ruby 之美。


謝邀。

什麼是美? 美就是簡潔、自然。Ruby做到了。

所以,Ruby的美學在於簡潔,而這種簡潔性,帶來的是你們所看到的一致性、靈活性、元編程魔法等閃耀特徵。其實要單論一致性的話,好多語言都是高度一致性的,所以說「一致性」還體現不出Ruby的美。

同樣的答案我在這個問題中也給出了回復:能否舉出各種例子,關於 ruby 可以做一件事用很多方法? - 知乎用戶的回答

--------------------- 還是粘貼過來吧,回答分割線 ----------

Ruby的第一設計哲學是簡潔,而Ruby本身確實也非常簡潔,正是因為這種簡潔性,才讓Ruby擁有了強大的能力,也許這是讓大眾真正迷惑的地方。

簡潔性主要體現在兩個方面:

一、 面向對象實現的簡潔性。

Ruby的對象模型,其實沒有那麼複雜,主要體現在四點:

1. 一切皆對象

2. 對象之間相互發送消息來通信

3. 單繼承

4. Duck Typing

Ruby中一切皆對象,意思就是,你在Ruby中看到的任何元素都是對象。而對象之間的通信,叫「消息發送」:

object.message

對象和消息,是Ruby中最本質的東西。

Ruby通過單繼承,簡化了多繼承。 這句話的意思是,Ruby中,類的繼承固然是單繼承,但是將模塊mixin到類中,這也是單繼承。不管你在類中include多少模塊,其實對於那個類來說,只有一個單繼承樹。這就簡化了Ruby中的方法查找。而Ruby的方法查找,我們剛才說了,就是對象間的消息傳遞的基礎。

而Duck Typing,也是基於對象和消息這種模型來設計的,這是一種對多態的簡化。不管這個對象是什麼類型,它只要滿足這種行為,也就是說,它只要能響應這個消息,那麼它就是對的「對象」。

所以,當你想調用某個方法,那就給那個對象發消息就可以了。而對象能不能響應到這個消息,這就涉及到消息(方法)定義和查找的問題。

二、元編程實現的簡潔性

Matz放棄了Lisp風格的宏,但不是放棄宏,他通過對Ruby詞法作用域的巧妙設計和block(細節寫這裡就太多了,參考我將在2016年完成的書或視頻吧),完美的實現了Ruby風格的「宏」,也就是我們Rubyist口中常說的「元編程」。而元編程要解決的問題,就是方法如何定義、如何查找和如何響應

我把Ruby提供的元編程相關方法,分為以下三類:

# 方法如何定義

def

define_method

method_missing

const_missing

# 方法響應

send

閉包 eval/bind、lambda/proc

block

反射

#方法如何查找(方法在哪定義)

class_eval

module_eval

instance_eval

class &<&< self

self

include

extend

open class(monkey patch)

下面是舉例:

我想列印hello world,有不同的方式:

1. 我可以直接在頂級作用域中打出來

puts "hello world" #=&> "hello world"

2. 我創建自己的類,並用此類的實例對象列印。這是在類的作用域中定義方法。

class A
def say
puts "hello world"
end
end

a = A.new
a.say #=&> "hello world"

當然,我可以用send方法來直接給對象發送消息:

a.send(:say) #=&> "hello world"

3. 我可以創建類方法。這是在元類中定義方法。

class A
def self.say
puts "hello world"
end
end

# or
class A

class &<&< self def say puts "hello world" end end end A.say #=&> "hello world"

4. 我可以在模塊中定義方法,並mixin。這利用了Ruby簡化單繼承鏈來實現多繼承。

module B
def say
puts "hello world"
end
end

class A
include B
end

a = A.new
a.say #=&> "hello world"

5. 還是在模塊中定義方法,只不過mixin到類的元類作用域中。

module B
def say
puts "hello world"
end
end

class A
extend B
end

A.say #=&> "hello world"

6. 我可以使用method missing,讓類在找不到方法的時候,返回hello world

class A
def method_missing(m, *args, block)
puts "hello world"
end
end

a = A.new
a.say #=&> "hello world"

7. 我可以在類外面直接打開相應作用域定義say方法

class A; end
A.class_eval do
def say
"hello world"
end
end

a = A.new
a.say #=&> "hello world"

#or

class B; end
B.instance_eval do
def say
"hello world"
end
end
B.say #=&> "hello world"

大概就舉這些例子吧。


定義DSL的能力 比如經典的Sinatra的DSL

get "/" do
"hello world!"
end

雖然DSL block用多了可能不小心會這樣... 摘自一個Grape的api代碼...


忘了是哪個紙糊的答案,意思是說,賈娃白富美,派森綠茶表,茹碧站街女。如此這般,美學特點請自行腦補(逃


Ruby提供了恰到好處的抽象,second class的block與動態類型相結合,使我們可以寫出非常自然的代碼.


ruby 的 Hash類型

有這麼些個方法

has_key?

include?

key?

member?

都是判斷 hash 里是否存在 某個特定的key

你可以按自己的喜好來用其中某一個

我選擇key?

因為短


推薦閱讀:

寫一個實用水平的編譯器有多難,多大工作量?
直接看 ISO C++14 的標準文檔學習 C++ 可行嗎?
為什麼很少有用lisp描述演算法?
c和c++這類沒有gc的語言是不是騙自己?
如果沒有PGO,JIT 編譯相比AOT 編譯有哪些優勢?

TAG:編程語言 | Ruby |