Ruby 自检系列

本文基于 ruby-triviaruby-style完成,节选部分问题,并更进一步探究原理,用以加强自身对ruby基础的理解和应用。

Language Characteristics and Core Objects

Q: Is Ruby a statically typed or a dynamically typed language?
A: Dynamically typed since type checking is done at runtime.

Q: Is Ruby a strongly typed or a weakly typed language?
A: Strongly typed since an object's type is checked before an operation is performed on it.

Q: What is the difference between a statement and an expression in Ruby?
A: All statements are expressions in Ruby since all statements return a value.
(expressions > statements)

Data Types

Q: Does String include the Enumerable module?
A: No.

Q: What method might you use to enumerate over a string?
A: String#each_char

Hash

Q: How might you specify a default value for a hash?
A: Pass the default values as arguments to ::new on initialization or change the default directly with the method Hash#default. You may also provide a default at the time of query with Hash#fetch.
C: 在某些情况下使用Hash#fetch是比较合适的:

  • 当处理应该存在的哈希键时,使用 Hash#fetch
heroes = { batman: 'Bruce Wayne', superman: 'Clark Kent' }

# 差 - 如果我们打错了哈希键,则难以发现这个错误
heroes[:batman] # => 'Bruce Wayne'
heroes[:supermann] # => nil

# 好 - fetch 会抛出 KeyError 使这个错误显而易见
heroes.fetch(:supermann)
  • 当为哈希键的值提供默认值时,倾向使用 Hash#fetch 而不是自定义逻辑。
batman = { name: 'Bruce Wayne', is_evil: false }

# 差 - 如果仅仅使用 || 操作符,那么当值为假时,我们不会得到预期结果
batman[:is_evil] || true # => true

# 好 - fetch 在遇到假值时依然可以正确工作
batman.fetch(:is_evil, true) # => false
  • 当提供默认值的求值代码具有副作用或开销较大时,倾向使用 Hash#fetch 的block形式
batman = { name: 'Bruce Wayne' }

# 差 - 此形式会立即求值,如果调用多次,可能会影响程序的性能
batman.fetch(:powers, obtain_batman_powers) # obtain_batman_powers 开销较大

# 好 - 此形式会惰性求值,只有抛出 KeyError 时,才会产生开销
batman.fetch(:powers) { obtain_batman_powers }

Q: Does Hash use #== or #eql? to compare hash keys?
A: #eql?
C: Why? What's the different between them?
Hash使用#eql?来做比较。而Numeric则是通过 #==做比较,而不是#eql?。在这种情况下,#eql?会做更严格的比较。
对于Object的对象, #eql? 是跟 #== 一样的。由此可知,Numeric是例外

equal? 则检查两者是否是同一对象(相同值,相同type)。

#对于 Numeric
x = 1
puts x.object_id  # => 3

y = 1
puts y.object_id  # => 3

z = 1.0
puts z.object_id  # => -36028797018963966

x == y  # true  同一个object
x.eql? y  # true 同一个object

x == z   #true 不同object,但是content相同
x.eql? z  #false 不同object,并且是不同的type,x是Fixnum,y是Float

#对于 Array object
x = [1, 2, 3]
y = [3, 2, 1]
z = [1, 2, 3]

x.object_id  # => 70244601475800
y.object_id  # => 70244601492000
x.eql?(y) #=> false

x.object_id  # => 70244601475800
z.object_id  # => 70244601475800
x.eql?(z) #=> true

x.object_id  # => 70244601475800
s = y.sort  # => [1, 2, 3]
s.object_id  # => 70244618664060
x.class # => Array
y.class # => Array
x == s #=> true  相同value
x.eql?(s) #=> true  相同value和type
x.equal?s  #=> false 相同value和type,但是不是同一个对象

Q: What's is the precedence of &&, and, or, =, ||?
A: && > || > = > (and, or)

Q: . vs ::
A: 调用类方法时,他们没有区别。但是使用::可以访问constant和namespace

Q: != vs <=>(spaceship)
A: != 不等于。 <=>,左边大于右边则返回1,等于返回0,小于返回-1

Q: What's true and false in ruby?
A: Everything in Ruby is true except false and nil.
TrueClass, FalseClass, but can't create a new instance for them. true and false are the only things we can get.
We can recognize them by either using nil? or false on == left-hand.

Q: What is duck type?
A: Walk like a duck, yip like a duck, it's a duck. In an other word, interface over type.

Q:

h = Hash.new
h[:s] = 'ok'

Can you retrive 'ok' by h['s'] ?
A: You cannot. Since the Hash class in Ruby’s core library retrieves values by doing a standard == comparison on the keys. This means that a value stored for a Symbol key (e.g. :my_value) cannot be retrieved using the equivalent String (e.g. ‘my_value’). On the other hand, HashWithIndifferentAccess treats Symbol keys and String keys as equivalent so that the following would work:

Q:#joins vs #includes in Rails ActiveRecord
A: #joins performs an inner join between two tables.

orders = Order.joins(:listing)
=> SELECT "orders".* FROM "orders" INNER JOIN "listings" ON "listings"."id" = "orders"."listing_id"

内连接。对于 T1 中的每一行 R1 ,如果能在 T2 中找到一个或多个满足连接条件的行, 那么这些满足条件的每一行都在连接表中生成一行。In another word, It will retrieve all records where listing_id (of orders table) is equal to listing.id (listings table)

这时候并没有listing的数据被取出。所有如果要取某个order的关联关系listing的属性,还是回去查一次数据库:

order_1 = orders.first
//上个命令的执行结果被存在内存中了, 直接读取了。
=> #<Order id: 1, customer_id: 1, listing_id: 1, product_id: 1, created_at: "2016-04-08 02:30:16", updated_at: "2016-04-08 02:30:49", status: "paid">

order_1.listing.address
//但具体关联到某个order上的listing信息还在数据库中,需要进行一次查询。
=> SELECT  "listings".* FROM "listings" WHERE "listings"."id" = $1 LIMIT 1  [["id", 1]]

#includes performs a left outer like join between the two tables.

orders = Order.includes(:listing)
=> SELECT "orders".* FROM "orders"
=> SELECT "listings".* FROM "listings" WHERE "listings"."id" IN (1, 2, 3, 4)

这时候执行的是类似于左外连接。
左外连接:首先执行一次内连接。然后为每一个 T1 中无法在 T2 中找到匹配的行生成一行, 该行中对应 T2 的列用 NULL 补齐。因此,生成的连接表里总是包含来自 T1 里的每一行至少一个副本。
为什么说是‘类似左外连接’?正常的左外连接应该是这样写的:

SELECT "orders".* FROM "orders" LEFT JOIN "listings" ON "listings"."id" = "orders"."listing_id";

但是在rails中我们并没有看到。这是因为在rails4中,我们需要手动写LEFT OUTER JOIN的sql查询语句:

orders = Order.joins('LEFT OUTER JOIN "listings" ON "listings"."id" = "orders"."listing_id"')

其实rails帮我们做的是先把所有orders表里的记录取出。然后再在listings表中取出可以跟orders表记录匹配的记录,并存在内存中。

好消息是rails5中加入了一个新方法#letf_outer_joins来执行LEFT OUTER JOINS.

这时候我们再来执行一次查询某个order的关联关系listings上的属性:

order_1 = orders.first
//从内存中取
=> #<Order id: 1, customer_id: 1, listing_id: 1, product_id: 1, created_at: "2016-04-08 02:30:16", updated_at: "2016-04-08 02:30:49", status: "paid">

order_1.listing.address
//因为listings表中的相应记录已经在第一步中被取出,所以这时候直接从内存中读即可。
 => {"city"=>"Nantes (44000)", "street_number"=>"", "region"=>"Pays de la Loire", "street"=>""}

可见,再次查询的时候并不会去读数据库。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容