本篇有一个区块的code,是一些常见问题在code中的长相以及用法,里面有一个非常阳春的名字检测器,可以利用运行时,使用者输入的名字来检测。
code中会看到两种符号#**
与@@
。
#**
部分就是常见问题。
请说明attr_accessor
今天内容有
类别变数,实体变数差异? 今天内容有
Ruby中self的意思?
请说明类别方法or实体方法差异
Ruby中private的用法
#@@
部分只是单纯想分享。
initialize与new的差别? 今天内容有
参数加等号。 今天内容有
yield if block_given? 今天内容有
脚本区会一起说到以下内容gets.chomp()
,sleep的用途
。
外部脚本可不可以直接改物件的资料。
class Elden_ring
attr_accessor :name, :role, :power #**
@@bad_word = ["脏", "坏", "衰", "呵"] #**
def initialize(name = "殭屍", role = "反派", power = 20) #@@
@name = name
@role = role
@power = power
end
def named
yield if block_given? #@@
new_name = gets.chomp() #@@
if bad_name?(new_name)
puts "名字含有不好的字元或空白,请重新输入"
named() #@@
else
self.name = new_name #**
puts %{是的! 原来他叫"#{self.name}"!} #@@
end
end
# class << self #类别方法 #**
# def fake_new
# Elden_ring.new("隐藏大魔王", "玩家", "unlimited")
# end
# end
# private #**
def bad_name?(new_name)
((new_name.split"") & @@bad_word) != [] || new_name == ""
end
end
##下面是脚本区。 也可将两个区块分开,利用`require`来运行
gwyn = Elden_ring.new("葛温", "薪王", "is Over 9000!")
ash = Elden_ring.new("不死镇杂鱼", "战士")
ash.bad_name?(ash.name) #测试private用
puts "#{gwyn.name},祂的职业是#{gwyn.role}。
他的力量#{gwyn.power}"
sleep 2 #@@
puts "\n有一天,有一个#{ash.name}。","是一个力量只有#{ash.power}的#{ash.role}杂鱼。"
sleep 2
puts %{\n#{ash.name}它身为杂鱼,平时非常羡慕"#{gwyn.name}"的存在
它希望自己能像"#{gwyn.name}"一般,成为'神族的一员'!
}
sleep 2
puts "%s\n%s" % ["这天,它做出了杂鱼不可能会出的一件事!", "它坐下冥想...."]
sleep 2
["一年过去了...", "两年过去了...", "三年...", "四年...", "整整五年的时间。"].each{|str|puts str; sleep 2}
ash.named do
prompt = '> '
puts "它想起了它拥有一个古老的名字!"
puts %{#请帮忙输入新名字#}
print prompt
end
sleep 2
puts "感谢参与测试!"
# boss = Elden_ring.fake_new #测试类别方法用
# puts boss.name
# ash.fake_new
是一个Module类别定义出来的方法,由於许多类别常需有取得器(getter)
与设定器(setter)
的需求,以方便操作改写资料与读取,所以直接设计attr_accessor
方法,不是取代getter与setter,是会直接帮你生成这两项的相对应方法,常直接写在类别上方,也更清楚这类别中有哪些资料可以取得及设定。
如果自己设定getter
与setter
,名字随意取也可以,但依照惯例尽量取相同例如下方示范,def name
就给@name
,这习惯到Rails後也是,保持这习惯,开发速度也会比较快。
不用眼睛花掉还找不到当初自己设定的名字是什麽!
用途?
#取代getter与setter
class Fake_class
def initialize(name = "金三角")
@name = name
end
def name #getter methods,取得物件内资料。
@name
end
def name=(new_name) #setter methods,设定物件内资料。
@name = new_name
end
def change_name(name) #有setter 这类方法才能执行
@name = name
def
end
2.7.3 :052 > abc = Fake_class.new
=> #<Fake_class:0x00007f923942cc28 @name="金三角">
2.7.3 :053 > abc.name
=> "金三角"
2.7.3 :054 > abc.change_name("泰山")
=> "泰山"
2.7.3 :055 > abc.name
=> "泰山"
使用attr_accessor
後,就可以少设定
class Fake_class
attr_accessor :name
def initialize(name = "金三角")
@name = name
end
end
irb输入完後可以输入.methods,可以看到:name 与:name= 方法。
attr_writer
=> 只生成setter
attr_reader
=> 只生成getter
如果可以,不要因为懒惰而都只用attr_accessor
,有些资料确定只能读取,而不希望被改变就使用attr_reader
,有些资料可以更动,但不希望被读取那就attr_writer
,虽然进入框架後(不只是Rails),可能也不会再需要手动设定这些,但是知道自己哪些资料该怎麽处理的观念还是要有。
不确定变数有几种,可以请看看龙哥的,为你自己学Ruby on Rails:变数(variable)
少用类别变数
这是实体变数@variable
class Evil_soul
@name = "恶魔灵魂"
def self.name
p "#{@name}!"
end
end
2.7.3 :074 > Evil_soul.name
"恶魔灵魂!"
=> "恶魔灵魂!"
#建立一个子类别
class Dark_soul < Evil_soul
@name = "黑暗灵魂"
end
2.7.3 :078 > Dark_soul.name
"黑暗灵魂!"
=> "黑暗灵魂!"
两个类别的@name不会互相干扰
即使继承後也一样。
2.7.3 :079 > Evil_soul.name
"恶魔灵魂!"
=> "恶魔灵魂!"
如果使用类别变数@@variable
class Evil_soul
@@name = "恶魔灵魂"
def self.name
p "#{@@name}!"
end
end
2.7.3 :087 > Evil_soul.name
"恶魔灵魂!"
=> "恶魔灵魂!"
class Dark_soul < Evil_soul
@@name = "黑暗灵魂"
end
#一被继承,如果新类别也有用这个类别变数,类别变数马上改变。
2.7.3 :091 > Evil_soul.name
"黑暗灵魂!"
=> "黑暗灵魂!"
少用类别变数比较好,避免类别被继承後,类别变数会马上改变,因为类别变数在同一条继承链上所有的类别是共用的。实体变数作用在单一类别内,而且两实体间互相不受影响。
当然更不适合直接用全域变数,这只是测试,我只放四个字,如果是很多内容的资料,应该放在别处。
initialize
与new
的差别?
先设定一个class。
class Init_test
def some(name = "测试", methods ="200种")
@name = name
@methods = methods
end
end
#这个类别new之後,只有给记忆体编号。
2.7.3 :118 > test = Init_test.new
=> #<Init_test:0x00007feb2a377dd8>
2.7.3 :068 > Init_test.some
Traceback (most recent call last):
NoMethodError (undefined method `some' for Init_test:Class)
#这样设定some是实体方法,Init_test用不了。
可以发现,故意设定一种内容跟initiailize
方法,是毫无反应的。
class Init_test
def initialize(name = "测试", methods ="200种")
@name = name
@methods = methods
end
end
2.7.3 :126 > test = Init_test.new
=> #<Init_test:0x00007feb2a30e1f8 @name="测试", @methods="200种">
用initialize才有除了记忆体编号外,有其他"数值"存在。
也代表initialize与new有"联动"。
#如果这样是会动。
class Init_test
def new(name = "测试", methods ="200种")
@name = name
@methods = methods
end
end
2.7.3 :133 > Init_test.new
=> #<Init_test:0x00007feb2a366948 @name="测试", @methods="200种">
但这样等於你把Ruby原本设定好的new
方法更动了,请不要这样。
new
方法使用时,会自动调动initialize
方法,利用初始化来,建构物件的"长相",所以我们更动initialize
就会自动调整到new
方法。而如果直接动new
方法,那你得先确认new
方法里会不会有你不知道的内容了。
initialize
在其他语言是建构子的概念(英语: Constructor,有时简称 ctor)
def some_method(num = "123")
num.to_i
end
这样代表如果我们没输入参数,会自动以预设值处理。
2.7.3 :099 > some_method()
=> 123
2.7.3 :100 > some_method(567)
=> 567
#进入有连接资料库的阶段後,要更注意资料栏位的Type,以及自己设定的方法之使用对象。
2.7.3 :111 > some_method([1, 2, 3])
Traceback (most recent call last):
NoMethodError (undefined method `to_i' for [1, 2, 3]:Array)
虽然阳春,还是有几个小小小细节说明一下。
原本code长这样。
def named
prompt = '> '
puts "它想起了它拥有一个古老的名字!"
puts %{#请帮忙输入新名字#}
print prompt
new_name = gets.chomp()
if ((new_name.split"") & $bad_word) != [] || new_name == ""
puts "名字含有不好的字元或空白,请重新输入"
named()
else
self.name = new_name
puts %{是的! 原来他叫"#{self.name}"!}
end
end
#下面这四行,不是没有意义,但我写在方法里,等於写死了台词。
prompt = '> '
puts "它想起了它拥有一个古老的名字!"
puts %{#请帮忙输入新名字#}
print prompt
#而我使用yield出去後,如果我想换台词,只需要在脚本区内用到的地方,其block区更改内容即可。
object.named {puts "这样便利多了"}
yield if block_given?
与 named
方法又出现了named()
。方法内再执行一次同方法算是常见手法,等於是跑回圈的一种,可以不用再看到loop
,while
,for..in
。用多了会发现很好用。
yield if block_given因为我只是请方法再帮我执行一次方法,我第二次并没有给予block。
yield
就是去block
。
要提这个是与rails里的错误处理机制一样,属於比较柔性的处理方式。
回到code。
((new_name.split"") & $bad_word) != [] || new_name == ""
常用会用到的行为,不如直接多建立一个方法。
大家都会用到的行为,不如直接建立一个模组。
所以直接建立了一个bad_name?()
def bad_name?(new_name)
((new_name.split"") & @@bad_word) != [] || new_name == ""
end
可以看到整个检验器非常简单,不是因为我检测资料只有4个字,是因为功能只有拆开输入的字串,再去与检测资料比对,而如果是希望检测名字内有没有敏感的词句,或敏感时事人物名字时,又该如何处理。
那当然是我另外一篇文章的事了
明日从self继续
今日的Leetcod.453. Minimum Moves to Equal Array Elements
题目连结:https://leetcode.com/problems/minimum-moves-to-equal-array-elements/
题目重点:一次可以动n-1
个元素来加1(今天是单纯数学题。)
# @param {Integer[]} nums
# @return {Integer}
def min_moves(nums)
end
puts min_moves([1,2,3]) #=> 3
puts min_moves([1,1,1]) #=> 0
炼金术士题..
sum = 初始所有数组和
n = 数组长度
m = 增加次数
x = m次完後会等於的数字
x * n = 最後数组的总和
min = 数组中最小的数
关系如下
sum + m*(n - 1) = x * n
由於增加数都是1,所以最後会等於的数字x = min + m,带入上一行公式。
sum + m*n - m = min*n + m*n
sum - m = min*n
m现在是我们唯一不知道的
sum - min*n = m
解完!
def min_moves(nums)
nums.sum - (nums.min * nums.size)
end
今天重点
1.说明attr_accessor
2.类别变数,实体变数差异?
3.Leetcod.453. Minimum Moves to Equal Array Elements
<<: @Day6 | C# WixToolset + WPF 帅到不行的安装包 [自订页面-官方UI页面结构]
>>: .NET Core第6天_如何将asp.net core应用部属到IIS_透过visual studio
在规模较大的企业网路中,为了避免单点故障会采用 LACP 的方式将多条线路聚合在一起使用,除了增加...
前天 Epic 跟 Apple 的诉讼第一次出结果,Apple 被判要在 90 天内开始允许所有 A...
Kamusta,我是Charlie! 在Day14中,我们完成了前端的购物车商品显示跟加入购物车,而...
什麽是 Serverless ? 若要将应用程序部属到生产环境,会需要考虑很多问题,包括计算资源是否...
今天开始要讲分散式系统的一些概念罗。 影片在此: Day04_关於分散式系统的一些概念 (一) ...