D-23. Self的意思、实体方法与类别方法、Private方法 && Minimum Moves to Equal Array Elements II

Ruby中self的意思?

Ruby Guides
What is self, exactly? It’s a Ruby keyword that gives you access to the current object.

先看个在irb中的self

2.7.3 :100 > def coffee
2.7.3 :101 >   puts self
2.7.3 :102 > end
 => :coffee
2.7.3 :103 > coffee()
main
 => nil

为何印出main?

答案是:Because it’s the name of the top-level object, it’s an object where you’ll find all the methods defined outside a class.
就结束了,问题这个top-level object到底在哪?

在这里

2.7.3 :001 > is_a?Object
 => true
2.7.3 :002 > methods
 => [:irb_popb, :popb, :jobs, :fg, :source, :help, :inspect, :context, :kill, :exit, :to_s, :irb_quit, :quit, :irb_print_work.....略

Ruby for beginners
The top-level scope is an empty, anonymous object. All Ruby code starts in here.

简单的说,当执行irb时,irb都会先开好一个最上层的匿名top-level object,可以直接定义一堆方法类别,或是输入一堆资料,甚至开一个新.rb档,在运行前让在irb中的物件暂时的"独立存在",也是为何当离开重进後会一切需要从新输入。

有更感觉到为何可以输入什麽值,就马上会回传了吗?

2.7.3 :003 > 50
 => 50
2.7.3 :004 > "50"
 => "50"
2.7.3 :005 > {}
 => {}

补充:先随意定义一个method,也可以用下面方式找到喔

2.7.3 :009 > methods.include?(:meth_name)

self在class里时

class Ashen
  attr_accessor :role
  def initialize(name, role)
    @name = name
    @role = role
  end

  def one
    puts self
  end

  def kill_gwyn
    self.role = "薪王"
    puts self
  end
end

2.7.3 :078 > player = Ashen.new("Ash", "不死者")
 => #<Ashen:0x00007f8ef30d25f8 @name="Ash", @role="不死者">
 
2.7.3 :079 > player.one
#<Ashen:0x00007f8ef30d25f8>
 => nil
#与new出来时的时候记忆体编号相同。

2.7.3 :080 > player.kill_gwyn
#<Ashen:0x00007f8ef30d25f8>
 => nil
#与上面一样

2.7.3 :082 > player.role
 => "薪王"

所有操作都是指向new出来的player

Access to the current object。

class Ashen
  def self.say_something
    puts "灰烬成双,则火燃起"
    puts self
  end
end

2.7.3 :013 > Ashen.say_something
灰烬成双,则火燃起
Ashen
 => nil

self.say_something是定义类别方法的一种写法,可以看到puts self印出的是类别Ashen

文字游戏,Ashendefself.say_somethingAshen定义自己说些什麽。
Ashen.is_a? Object #=> true
无论如何self指的就是当前物件。

玩一下itself

2.7.3 :024 > 50.itself == Integer
 => false
2.7.3 :025 > 50.itself == 40
 => false
2.7.3 :026 > 50.itself == 50
 => true
2.7.3 :027 > 50.itself * 10
 => 500
2.7.3 :028 > [1, 2, 3].map{|num| num.itself.to_s}
 => ["1", "2", "3"]

请说明类别方法or实体方法差异

判断方式如self,看是谁在用,真的就这麽简单。
所以只介绍怎麽建立类别方法,一种上一段说了,现在讲比较好整理的写法。

昨天脚本有以下这段被标记起来的code。

class << self
  def fake_new
    Elden_ring.new("隐藏大魔王", "玩家", "unlimited")
  end
end

直接改造一下。

class Elden_ring
  def initialize(name = "殭屍", role = "反派", power = 20)
    @name = name
    @role = role
    @power = power
  end

  class << self
    def fake_new
      Elden_ring.new("隐藏大魔王", "玩家", "unlimited")
    end
  end
end

2.7.3 :044 > me = Elden_ring.new
 => #<Elden_ring:0x00007fd511af6ca0 @name="殭屍", @role="反派", @power=20>
 
2.7.3 :045 > me.fake_new
Traceback (most recent call last):
NoMethodError (undefined method fake_new for #<Elden_ring:0x00007fd511af6ca0>)

2.7.3 :046 > Elden_ring.fake_new
 => #<Elden_ring:0x00007fd511af4d60 @name="隐藏大魔王", @role="玩家", @power="unlimited">

fake_new只有Elden_ring能用喔,因为是类别方法。


Ruby中private的用法

昨天的范本,将private的注解取消後,在脚本区的ash.bad_name?(ash.name),就会马上使档案无法运行,会出现这样的错误<main>': private method bad_name?' called for #<Elden_ring:0x00007fe03e179758> (NoMethodError)

不是写在同一页吗?也没有故意拆分两个档案(正确应该要分开...),为何还是显示私有的?
原因是,private让方法只能在class的定义区内被使用。
反过来将ash.bad_name?(ash.name)注解掉,发现又可以继续正常运行脚本。

private写法

class Mine

  private
  def under_private_is_mine
  end
end

也可以这样

class Mine

  def some_methods
  end

  def i_am_private
  end
  private :i_am_private
end

由於网路上private三兄弟资料非常多,这边只补充一部分是,类别方法也可以private

2.7.3 :024 > Array.name
 => "Array"
2.7.3 :025 > Integer.name
 => "Integer"

class Test_list
  def self.name
    "中二"
  end
end

2.7.3 :031 > Test_list.name
 => "中二"

不是指这种私有喔!
而是如一般方法的私有。

class Abc

  def self.go_home
    way
  end

  class << self
  private
    def way
      puts "on my way!"
    end
  end
end

2.7.3 :014 > Abc.way #NoMethodError (private method `way' called for Abc:Class)
2.7.3 :015 > Abc.go_home
on my way!
 => nil

2.7.3 :016 > class Bcd < Abc
2.7.3 :017 > end
 => nil
2.7.3 :018 > Bcd.go_home
on my way!
 => nil

是的,类别方法可以私有,但看程序码应该可以发现privateclass_methods的继承没有限制效力。
这不是原理,这是原则喔,不然怎麽物件导向,不然怎麽类别继承。
看过网路文章有人钻牛角尖问这个问题,最後的回答是你应该去学其他语言


补充:()有时千万不要省略。

昨天code很明显有一个地方是不该省略( )的。
直接这边改写

2.7.3 :001 > bad_word = [1, 2, 3]
 => [1, 2, 3]
2.7.3 :002 > "123".split"" & bad_word == []
Traceback (most recent call last)
NoMethodError (undefined method `&' for "":String)
#依照提示修改

2.7.3 :003 > "123".split("") & bad_word == []
 => true

或是像我的丑写法

2.7.3 :004 > ("123".split"") & (bad_word) == []
 => true

常常code突然跳NoMethodError (undefined method ...,这类资讯,就该先检查一下是不是()在搞鬼了
另外还有要注意类似数学运算,执行权{}优先权大於[]大於()


脚本区运用到的一些小小小功能

sleep的用途。
暂停程序运行用,也可用在方法内喔。

def hi_and_hello
  puts "hi"
  sleep 2
  puts "hello"
end

执行後会停止运作,不过进入Rails後,前端交给js,不大会再看到了。
记得带参数,不要只有sleep()

gets.chomp()
这是看一本老书Learn Ruby The Hard Way看到的,因为版本问题不会很推荐看这本书,但是偶尔看看可以发现很多老玩家用的特殊写法,那些在中文资料内比较不好找到。

gets很明显是抓取方法。irb可直接利用。

2.7.3 :014 > gets

输入後会发现画面换行但是没动,不用担心,代表可以开始输入内容了。

2.7.3 :015 > gets
今天天气很好,我想要出门去玩!
 => "今天天气很好,我想要出门去玩!\n"

可以发现多了换行符号\n,我们改输入gets.chomp()()可省略。

2.7.3 :026 > gets.chomp
今天天气很好,我想要出门去玩!
 => "今天天气很好,我想要出门去玩!"

chomp作用是去除抓取字串最後面的跳脱字元。

2.7.3 :034 > gets.chomp
今天天气\n很好
 => "今天天气\\n很好"

在中间的没用喔。

补充chop

2.7.3 :037 > "很重要".chop
 => "很重"
2.7.3 :038 > "很重".chop
 => "很"
2.7.3 :039 > "很".chop
 => ""

puts你不用知道但知道比较酷的技巧?
**irb模式变成程序一部分再输出有时会有不一样效果喔
主要说明於method内的puts

请用\n

def test_puts
  puts "123\n456\n789"
end
2.7.3 :075 > test_puts()
123
456
789
#puts "123
#456
#789"  方法内这样不会出事,比较不好看而已

想要""内有""或特殊符号,%{}

def test_puts
  puts %{"1-9"~!@#$%^&*()_+-=}
end
2.7.3 :079 > test_puts()
"1-9"~!@#$%^&*()_+-=

%w() => 如果不想一直打""

def test_puts
  string = %w(今天 天气 有够好 对不对)
  puts string
end
2.7.3 :084 > test_puts()
今天
天气
有够好
对不对

puts <<-EOF ....... EOF可以缩排效果

def test_puts
  puts <<-EOF
  一阵操作猛如虎
      一看战绩零杠五
  EOF
end

2.7.3 :122 > test_puts()
  一阵操作猛如虎
      一看战绩零杠五

%s真的想不到什麽地方可以用了..因为有each呀

def test_puts
  puts "%s\n%s" % ["一顿操作猛如虎","一问薪水二百五"]
end
 => :test_puts
2.7.3 :131 > test_puts()
一顿操作猛如虎
一问薪水二百五


def test_puts
  strings = ["床前明月光", "疑似地上霜", "举头望明月", "低头吃便当"]
  strings.each{|string| puts string}
end
2.7.3 :136 > test_puts()
床前明月光
疑似地上霜
举头望明月
低头吃便当

了解一些就好,设计师们会帮你烦恼这块的....


物件更改hash内的key与value

这部分到Rails後,会被Migration取代,毕竟连接着资料库,需要更安全正确的手段才能动资料库。
也更不应该随便手动去更改资料库的内容。

Has的key相对於每个column名称,value相对於column的值。
在Ruby时我们有许多方式去更改其中的key或value。

2.7.3 :137 > id_1 = {:name => "索拉尔" , :role => "太阳战士", :belief => "太阳长男", :power => 250}
 => {:name=>"索拉尔", :role=>"太阳战士", :belief=>"太阳长男", :power=>250}
2.7.3 :140 > id_1[:name] = "猎龙者"
 => "猎龙者"

#改key
2.7.3 :146 > id_1 = {:name => "索拉尔" , :role => "太阳战士", :belief => "太阳长男", :power => 250}
 => {:name=>"索拉尔", :role=>"太阳战士", :belief=>"太阳长男", :power=>250}
2.7.3 :147 > id_1[:title] = id_1.delete :name
 => "索拉尔"
2.7.3 :148 > id_1
 => {:role=>"太阳战士", :belief=>"太阳长男", :power=>250, :title=>"索拉尔"}

#加入新的key与值的其中一种方法。
2.7.3 :003 > h = {}
 => {}
2.7.3 :004 > h[:a]= 123
 => 123
2.7.3 :005 > h
 => {:a=>123}
2.7.3 :007 > h[:b] = 456
 => 456
2.7.3 :008 > h
 => {:a=>123, :b=>456}

解题的时,一些更改value与key的方法,都会是好方法,但记得到Rails後,不要这样对待资料库内的资料。
~~这段纯属碎碎念~


满一周了,纪念性的来一题中等难度的吧!
今天的Leetcod462. Minimum Moves to Equal Array Elements II
就昨天那题的II,不小心点到,不小心刚好想起最佳开会距离这个议题。
所以之後还是继续Easy题XD
题目连结:https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/
题目重点:随意选一个加1或减1,其实就是解答。

# @param {Integer[]} nums
# @return {Integer}
def min_moves2(nums)

end

puts min_moves2([1,2,3])  #=2
puts min_moves2([1,10,2,9]) #=16

[1, 2, 3]就可以看到答案。变成一样其实往中间跑最快。

2 = 3 - 1 #动一步
2 = 1 + 1 #动一步
1 + 1 = 2

换个例子[1, 5, 4]

#4是中位数
2.7.3 :016 > [1, 5, 4].sort!
 => [1, 4, 5]
#直接改变参数本体,之後直接计算,不用再多用到一个变数的记忆。
#往4跑
4 = 1 + 3 #动3步
4 = 5 - 1 #动1步

总共4步,记得有的是+,有的是-,+用x轴来说等於与中心点的位置是负的,-反之。
明明讲有正有负就好....

如果不相信这个原理,请想想两个人见面是往面对面的方向跑快,还是往同一边跑?
所以n个人,要见面,也是往中心点跑,但这题目中心点是固定的,在这n个人之中,所以选出n个人的中心点。

整理一下

nums.sort!.each
nums.sort!.map #用哪个都好,但是我用完each後直接改map,等等答案就会知道原因了。

muns.size/2 #中间值
|num| num - nums[muns.size/2]
#因为有正有负记得加Anti-Lock Brake System,开玩笑的.abs。
(|num| num - nums[muns.size/2]).abs # 每个都计算与中心点的绝对值

最後记得sum。
整理完如下

def min_moves2(nums)
  nums.sort!.map do |num|
    (num - nums[nums.size/2]).abs
  end
  nums.sum
end

def min_moves2(nums)
  nums.sort!.map {|num|(num - nums[nums.size/2]).abs}.sum
end

今天的重点
1.Ruby中self的意思?
2.请说明类别方法or实体方法差异
3.Ruby中private的用法
Leetcod462. Minimum Moves to Equal Array Elements II

明天讲继承与模组。


<<:  Day 07 : MLOps 的挑战与技术要求

>>:  [Day7] 隐式调用与显式调用是甚麽?

Day 01 - 前言

yo~ 原本写好了几个字 改一下主题就全清空拉 很QQ馁 不免俗的,这也是小女子第一次参加铁人赛 ...

虹语岚访仲夏夜-17(打杂的Allen篇)

感觉经历了一段乱流区,我走到柜台,跟太子点了杯冰咖啡,就在等咖啡的时候,门打开了,看到一个身影,坐到...

[Day12] CH08:积沙成塔——Array & ArrayList(中)

还记得我们前两天学的方法吗?结合昨天学的阵列,阵列也可以用在方法里传递吗? 当然可以罗!我们就先来看...

[DAY 11] _软件实现I2C协议以三轴感测器为例 (ADXL345)

昨天DAY10讲了控制GPIO口来完成协议,今天来讲实际的例子,以大家最常听过三轴感测器为例,首先介...

受信任计算机系统评估标准(TCSEC)

TCSEC定义了评估可信计算系统的标准,该系统包括四个分类。每个分类可以分为几类。B分类的类别(B1...