D-21. & 、meta programming & Monkey patch

&

常见使用&的状况如下

:007 > [1, 2, 3].map(&:to_s)
 => ["1", "2", "3"]

如果你的画面中字体有分颜色,可以发现&:to_s颜色不同。
Ruby中没有&:这个东西,其实是&symbol的组合。

间单的回答通常就是&生成{|nun|num }

:015 > [1, 2, 3].map {|int| int.to_s}
 => ["1", "2", "3"]
:016 > [1, 2, 3].map(&:to_s)
 => ["1", "2", "3"]

方法变参数的写法。

:032 > [1, 2, 3].each(&method(:puts))
1
2
3
 => [1, 2, 3]

而比较准确一点的说&object,&object的关系是。
1.如果objectproc&会把proc转换成block
proc用多了会忘记block != proc

以下有两种用法

def i_need_a_block(&block)
  puts "所以需要call"
  block.call
end

 :005 > i_need_a_block {puts "Block here!"}
所以需要call
Block here!

还有介绍过的yield

def i_need_another_block
  puts "我先不想看到&"
  yield
end

:010 > new_proc = proc {puts "但是不能没有&" }
 => #<Proc:0x00007fb0981cde78 (irb):10>
 :011 > i_need_another_block(&new_proc)
我先不想看到&
但是不能没有&

2.如果&对象不是proc,那就是&会试图调动对象内的to_proc方法。
这是symbolto_proc描述。

Returns a Proc object which responds to the given method by sym.

(1..3).collect(&:to_s)  #=> ["1", "2", "3"]

如果不想深究,可以记住的确就是协助产生{|num| num }这样的block
如果有兴趣。符号中的to_proc的定义方式大概长得像这样。

class Symbol
  def to_proc
    ->(obj, args = nil) { obj.send(self, *args) }
  end
end

下面的code出自於https://maximomussini.com/posts/ruby-to_proc/
说明了converts it to a block.

names.map &:to_s

# We can expand it to  &呼叫了symbol的to_proc
names.map &:to_s.to_proc

# Replacing "to_proc" with the result of calling the method
# 将上面的定义带入
names.map &->(name, args = nil) { name.send(:to_s, *args) }

# "map" passes a single argument to the block, so we can simplify
# map本身就具将参数迭代可看一段
names.map &->(name) { name.send(:to_s) }

# Calling the method directly we get
names.map &->(name) { name.to_s }

# Since "&" transforms Procs and Lambdas to blocks, it's equivalent to
names.map { |name| name.to_s }

另外提到了一个重点。

There’s nothing special about the shorthand &:method syntax. Ruby arbitrarily defines Symbol#to_proc in a way that allows programmers to avoid some boilerplate.
是的。愿意的话可以改写to_proc功能。

还可以看看&的炫酷用法。

:043 > %w(abs msd sddf).map(&:size).reduce(&:+)  #其实reduce里的&还可以省略
 => 10
:033 > hash = {a: 123, b: 456, c: 789}
 => {:a=>123, :b=>456, :c=>789}
:034 > [:a, :b, :c].map(&hash)
 => [123, 456, 789]

Monkey patchmeta programming

meta programming是一个概念。

meta programming常被翻译元程序设计,程序设计大概懂,就....
meta曾经看过一篇文章,忘记出处了,解释原文是希腊文,有之後超越的意思在,後面衍生为很像是about,例如metadata == data about data

直接看两句词典的meta例句:

It's a meta joke. It's sort of a joke about jokes.
这本身就是一个笑话。是一个关於笑话的笑话。

I am standing at my desk typing this about the media right now. It feels very meta.
我现在正站在办公桌前打这篇关於媒体的文章。我感觉就是在写自己。

很抽象,但看了这两句就懂维基百科说的了。

维基百科
元程序设计(英语:Metaprogramming),又译超程序设计,是指某类电脑程序的编写,这类电脑程序编写或者操纵其它程序(或者自身)作为它们的资料,或者在执行时完成部分本应在编译时完成的工作。多数情况下,与手工编写全部代码相比,程序设计师可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。

在Ruby这类动态语言且将资料都包装成一个个类别,我们处理任何object都是用Class本身自己的程序方法去处理,各Class已经将原本就抽象的object特性封装好了,就是一种meta programming方式,且因为这种方式,Ruby也能将本身语言非常口语化。

:012 > "reverse".reverse
 => "esrever"

Monkey patch是种描述。

open class也是前几天code中,一直有在做的事情。
Ruby自由到已经内建好的Class也可以让你修改。

:001 > [1, 2, 3].to_s
 => "[1, 2, 3]"

class Array
  def to_s
    self.map{|num|num.to_s}  #这里的to_s是Integer的to_s
  end
end

:007 > [1, 2, 3].to_s
 => ["1", "2", "3"]

当然也会衍生到这类open过的class_methods应该集中某处避免debug找不到,或是如何保留原本array.to_s功能等。

不过针对Monkey pathchRuby就是非常简单的,我们为了增加子类别功能或更改其中一个方法的作用,使用open class这项这性,对子类别的某个与上层同名的功能做修改的行为。
当然有人说,Monkey pathch属於不好的操作,易造成程序码杂乱,为了在执行层面得到正确资料,而对方法实施修改等。但学会将程序码整理好,不为了交差随便了事,才是成年人。况且,针对功能扩充应在於moduleopen class的用意是在让亲子层之间有所差异而操作。

判断句缩写,三元运算子

if aaa
  bbb
end
 => return bbb if aaa #return可省略

if aaa
  bbb
else
  ccc
end
 => aaa ? (bbb) : (ddd)  #()可省略,但是要注意有些方法不()起来会导致语法错误。

if aaa
  bbb
elsif ccc
  ddd
else
  eee
end
 => aaa ? bbb :(ccc ? ddd : eee) #()我没有勇气省略...

关於Ruby还有很多可以说。
但还是该进到Rails部分了,虽然一些问题是从Ruby衍生而来,但说明Rails的部分,自然Ruby也会说明到了。


今天的:Leetcode
392.Is Subsequence (指针题)
414.Third Maximum Number (单纯语法熟练度题)

392.Is Subsequence
题目连结:https://leetcode.com/problems/is-subsequence/
题目重点:会达成true,代表t一定是a的各元素中间穿插新的元素。

def is_subsequence(s, t)

end

puts ("abc", "ahbgdc") #=>true
puts ("axc", "ahbgdc") #=>false

画图时间,及我将例子更改为数字阵列。

[1, 6, 3, 7, 5] #=t
 &
 $        #慢指针 一开始设计为0
[1, 3, 5] #=s

#我们由t的指针当快指针
#index = 0

[1, 6, 3, 7, 5] #t第一个是1,请问s[0]是1吗?
 &
    $
[1, 3, 5] #=s是的,那我+1,请你帮我检查第2个。 index += 1

[1, 6, 3, 7, 5] #t第二个是6,请问s[1]是6吗?
    &
    $
[1, 3, 5] #=s 不是,我不动,请继续检查。

[1, 6, 3, 7, 5] #t第三个是3,请问s[1]是6吗?
       &
       $
[1, 3, 5] #=s 是,那我+1,请你帮我检查第3个。 index += 1

[1, 6, 3, 7, 5] #t第四个是7,请问s[2]是7吗?
          &
       $
[1, 3, 5] #no, next plz!

[1, 6, 3, 7, 5] #t第五个是5,请问s[2]是5吗?
             &
       $
[1, 3, 5] #yes, index += 1。

t如果超过五个,要继续跑也没关系,不可能再判断出相等,index也不会再+=

def is_subsequence(s, t)
  index = 0
  t.each_char do |str|
    index += 1 if str == s[index]
  end
  index == s.size
end

414.Third Maximum Number
题目连结:https://leetcode.com/problems/third-maximum-number/
题目重点:是不是还记得Rubymax可以抓指定前几个大的。少於三个元素的回报最大的就好。
max(?)太少用忘掉时,差点撞墙

def third_max(nums)

end

puts third_max([3,2,1])  #=> 1
puts third_max([1,2])  #=> 2
puts third_max([2,2,3,1])  #=> 2

题目第三个例子有提醒要uniq,还有元素少於3个回最大

 nums.max if nums.size < 3
 nums.uniq.max

第三大的 == 抓前三取最小

 nums.uniq.max(3).min

错误

def third_max(nums)
  nums.size > 2 ? nums.uniq.max(3).min : nums.max
end

因为例子有[1,1,2]。需要uniq。

可行的

def third_max(nums)
  nums.uniq.size > 2 ? nums.uniq.max(3).min : nums.max
end

今天提到的
1.& 是什麽
2.meta programming
3.Monkey pathch
4.Is Subsequence && Third Maximum Number


<<:  Day09 - 套用 Html Helper - 复杂型别 object + object collection

>>:  Day.1 起点 - 前言 ( Percona Server )

【Day 16】 介绍 AWS 中资讯安全 - 流量相关日志

大家午安~ 就以先前我们於 AWS 建置个人的 WordPress 网站举例(如下图所示),若要访问...

Day9:卷积神经网路(Convolutional Neural Networks,CNN)介绍

  卷积神经网路(Convolutional Neural Networks,以下称CNN)在图片和...

D-30-安装 vscode ? dotnet sdk

离实习结束还有30天 实习生小光第一天到新公司实习,什麽都不懂的他到底会遇到什麽事情呢,让大家想想第...

Day 6— 自动化回信机(3) 寄出信件功能

昨天我们终於把取得试算表内资讯的任务搞定了!接下来就是打勾之後,我们把信件寄出这个任务了! 首先,按...

[新手教学]如何使用Line Notify

首先登入到 LINE Notify 并进入到个人页面 接着选择要接收通知的聊天室,也可以透过一对一接...