Ruby 控制流程用法詳解

來源:互聯網
上載者:User

之前我們見過方法的調用,它會讓程式從調用方法的地方跳到方法的定義主體那裡。程式並不是按直線啟動並執行,執行的順序會受到一些規則還有一些被稱為控制流程的程式設計結構的影響。

Ruby 的控制流程有下面這些:

條件執行(Conditional execution)— 根據運算式的真實性執行。
迴圈(Looping)— 一塊兒重複執行的代碼。
迭代(Iteration)— 調用方法的時候給它提供一塊兒代碼,方法在它執行的時候可以多次調用這塊代碼。
異常(Exceptions)— 處理異常情況。
按條件執行代碼

Ruby 提供了一些基於條件控製程序流的方法。有兩大類,if 還有 case 。

if 跟它的朋友們

if 用起來像這樣:

if condition
  # condition 如果是 true 就執行這裡的代碼
end
if 可以嵌套使用:

if condition
  # condition 如果是 true 就執行這裡的代碼
  if condition2
    # condition2 如果是 true 就執行這裡的代碼
  end
end
if 可以放到一行用,在條件的後面使用關鍵詞 then,像這樣:

if x > 10 then puts x end
或者使用分號:

if x > 10; puts x; end
條件執行經常關係到多個分支,你可能想在條件成功的時候做點事,失敗的時候做另一些事兒。可以使用 else 或 elsif。用法是這樣的:

if condition
  # condition 是 true 就執行這裡的代碼
else
  # condition 是 false 就執行這裡的代碼
end
加上 elsif 可以繼續添加要判斷的條件:

if condition1
  # condition1 是 true 就執行這裡的代碼
elsif condition2
  # condition1 是 false
  # condition2 是 true 就執行這裡的代碼
elsif condition3
  # condition1 與 condition2 都是 false
  # condition3 是 true 就會執行這裡的代碼
end
做個實驗:

print "輸入一個整數:"
n = gets.to_i

if n > 0
  puts "你輸入的是正數"
elsif n < 0
  puts "你輸入的是負數"
else
  puts "你輸入的數字是 0"
end
再試一下否定形式的條件,可以使用 not 與 !,先試一下 not:

if not (x == 1)
再試一下 !  號:

if !(x == 1)
unless 跟 if not 與 if ! 的效果一樣,試一下 unless:

unless x ==1
19:59 **

21:15 **

if 還可以這樣用:

puts 'big number!' if x > 100
上面的代碼可以解釋為:

if x > 100
  puts 'big number!'
end
unless 也可以這樣用:

puts 'big number!' unless x <= 100
如果一個 if 聲明成功了,整個聲明的值會用成功的那個分支來表示,做個實驗:

x = 1

if x < 0
  '負數'
elsif x > 0
  '正數'
else
  '零'
end
irb 會告訴你上面的 if 整個聲明的值會是字串 '正數' 。如果 if 聲明沒成功,會返回 nil 。

21:37 **

條件主體裡的分配

2016年9月9日 上午8:52 ***

分配文法與條件運算式在兩個點有交叉,在條件運算式的主體裡,分配有可能發生也可能不會發生,還有就是在條件測試上:

if x = 1
  y = 2
end
x = 1 是條件測試裡的分配,y = 2 是條件主體裡的分配。

條件主體裡的分配

編譯語言有編譯時間,還有運行時這兩個說法。Ruby 是指令碼語言,在運行指令碼之前解譯器會解析代碼,這時候會做一些決定, 比如去識別與配置本地變數。

Ruby 解譯器看到這樣形式:識別符,等號,值,比如像這樣:

x = 1
解譯器會給 x 這個本地變數分配一個空間。

來看這個例子:

if false
  x = 1
end

p x
p y
上面的例子裡,分配 x 的動作並沒有被執行,因為它是在一個失敗的條件測試裡封裝著。不過 Ruby 的解譯器看到了 x = 1,推斷程式可能會用到本地變數 x ,解譯器不在乎 x 是不是得到了一個值。它會給 x 一個 nil 值,所以輸出 x ,得到的結果是 nil ,但是你輸出一個不存在的本地變數的時候,就會出現嚴重錯誤。

條件測試裡的分配

看個例子:

if x = 1
  puts 'hi'
end
上面在條件測試裡的東西是一個分配(x = 1),注意它並不是去比較是否相等,像 x == 1 。在條件測試裡的分配跟在其它的地方分配是一樣的,就是 x 的值設定成了 1。測試本身會認為條件是 if 1 ,也就是 true,這樣條件主體裡的東西會被執行,就會輸出一個 hi 。

同時你會看到一個警告:

warning: found = in conditional, should be ==
Ruby 會認為要測試的 if x =1 會一直成功,條件主體也就會一直被執行,所以 Ruby 會認為你可能是輸錯了,就會給你個警告提示一下,警告會建議你使用 == 操作符,它可以測試兩個值是否相等。

Ruby 知道這樣做不是一個錯誤:

if x = y
跟 x = 1 不一樣,x = y 作為條件測試不一定會成功。

上午9:37 ***

case

上午9:51 **

case 聲明用一個運算式開始,一般就是一個單獨的對象或者變數。然後是一些可能的匹配,每個可能的匹配都會包含在一個 when 聲明裡,它裡面還有一塊兒代碼。最終只會有一個匹配勝出,然後就會執行這個 when 裡面的代碼。

瞭解 case 的使用,先來看個例子:

print '是否退出?(yes/no):'
answer = gets.chomp

case answer
when 'yes'
  puts '再見!'
  exit
when 'no'
  puts '我們繼續!'
else
  puts '不知道您在說啥,假設是 no'
end

puts '繼續程式 ... '
一個 case 聲明,使用 case 這個關鍵詞開始,然後就是一個 when 區塊,還有一個可選的 else ,結束 case 要使用一個 end 關鍵詞。只有一個匹配會最終勝出,然後去執行它裡面的代碼。上面的例子裡,如果輸入的是 “yes”,程式就會退出。如果是 “no" 或其它的值,會讓程式可以繼續運行。

在一個 when 裡面,你可以添加多個匹配:

case answer
when 'y', 'yes'
  puts '再見!'
  exit
  # etc
上面的例子,我們在 when 裡面使用逗號分隔開了一些可能的匹配,它有點像是 或 操作符。上面的意思是如果輸入是 “y” 或 “yes” 就輸出 “再見” 並退出程式。

when 是怎麼一回事兒

每個 Ruby 對象都有一個 case equality 方法,名字是 === ,調用 === 的結果就是判定一個 when 是不是被匹配了。

上面的例子,我們可以這樣重寫一下:

if 'yes' === answer
  puts '再見!'
  exit
elsif 'no' === answer
  puts '我們繼續!'
else
  puts '不知道您在說啥,假設是 no'
end
站在中綴操作符(infix operator)的角度看 === ,它其實就是方法的 Syntactic sugar:

if 'yes' .===(answer)
再看一下為什麼當 answer 包含 yes 的時候會返回 true:

'yes' === answer
調用三等(===)方法會返回 true,是因為三等方法是為字串定義的。當你問一個字串它自己是不是三等另一個字串(string1 === string2),你問的其實就是字串自己的內容,一個一個的跟另一個字串去比較,如果匹配,就會返回 true,不然就會返回 false。

每個類都可以定義自己的 === 方法,可以用自己的 case-equality 邏輯。

case/when 就是 object === other_object 的偽裝,object === other_object 其實是 object. === (other_object) 的偽裝。

對象 case 行為

class Ticket
  attr_accessor :venue, :date
  def initialize(venue, date)
    self.venue = venue
    self.date = date
  end

  def ===(other_ticket)
    self.venue === other_ticket.venue
  end
end

ticket1 = Ticket.new('Town Hall', "07/08/13")
ticket2 = Ticket.new('Conference Center', "07/08/13")
ticket3 = Ticket.new('Town Hall', "08/09/13")

puts "ticket1 的位置是: #{ticket1.venue}"

case ticket1
when ticket2
  puts '跟 ticket2 在同一個位置'
when ticket3
  puts '跟 ticket3 在同一個位置'
else
  puts '沒有匹配'
end
執行的結果是:

ticket1 的位置是: Town Hall
跟 ticket3 在同一個位置
傳回值

如果在 when/else 從句裡有成功的,case 聲明返回的值就是執行這個雙句裡的代碼的結果。如果要匹配的全都失敗了,整個聲明就會返回 nil 。

上午10:40 ***

Loops

上午11:02 ***

無條件迴圈

使用 loop,像這樣:

loop codeblock
代碼塊有兩種形式,一種是使用花括弧({}),一種使用 do 還有 end 操作符。下面的例子示範了這兩種形式:

loop { puts 'looping forever!' }

loop do
  puts 'looping forever!'
end
你不能讓迴圈永遠繼續下去,你需要讓它在某個點上停下來。

控制迴圈

使用 break 關鍵詞:

n = 1
loop do
  n = n + 1
  break if n > 9
end
使用 next 跳過當前的迴圈:

n = 1
loop do
  n = n + 1
  next unless n == 10
  break
end
有條件迴圈

有條件的迴圈用的關鍵詞是 while 與 until 。

while

一個條件如果是 true 就去迴圈。用 while 開始,end 結束,在它們之間的代碼就是每次迴圈要執行的東西:

n = 1
while n < 11
  puts n
  n = n + 1
end
puts '完成!'
上面這塊代碼輸出的是:

1
2
3
4
5
6
7
8
9
10
完成!
n < 11 這個條件是真,迴圈就會被執行。每次迴圈的時候 n 的值都會增加 1 。

while 也可以放到迴圈的結束,要配合使用 begin/end 關鍵詞:

n = 1
begin
  puts n
  n = n + 1
end while n < 11
puts '完成!'
while  放在開始與結尾有點區別,如果你把 while 放在開始的地方,條件如果是 false ,迴圈一次都不會被執行。但是如果你把 while 放在結尾,如果 while 條件是 false,迴圈會被執行一次。

until

n = 1
until n > 10
  puts n
  n = n + 1
end
迴圈的主體會被執行,直到條件是 true。

while 與 until 修飾符

使用 until:

n = 1
n = n + 1 until n == 10
puts '數到 10 了!'
也可以使用 while:

n = 1
n = n + 1 while n < 10
puts '數到 10 了!'
做個實驗:

a = 1
a += 1 until true
a 的值仍然是 1 ,因為 true 已經是 true 。

再做個實驗:

a = 1
begin
  a += 1
end until true
在 begin 與 end 中間的代碼會被執行一次。

迴圈一個列表的值

做個實驗:

numbers = [1, 2, 3]
for n in numbers
  puts n
end
執行的結果是:

1
2
3
上午11:30 ***

迭代

下午6:51 **

迭代器的原料

在一個對象上調用方法,控制會傳遞給方法的主體(一個不同的範圍),方法執行完以後,控制會返回給調用方法的那個地方之後的點上。再來認識兩個新的結構,代碼塊(code block) 還有關鍵詞 yield 。

之前我們看見過這樣一個例子:

loop { puts 'looping forever!' }
上面的代碼會一直輸出那個資訊,想一下,這到底發生了什嗎?在 loop 裡為什麼會執行 puts 。答案是:loop 是一個迭代器。迭代器是一個 Ruby 方法,調用這種方法的時候需要加點特別的料,它會期望你給它提供一個代碼塊。一個大括弧就會劃分出來一個代碼塊。

loop 方法可以存取碼塊裡的代碼,就是方法可以調用或者叫執行這個代碼塊。想讓自己的迭代器可以做這件事,你就可以使用關鍵詞 yield。代碼塊與 yield 就是一個迭代器的主料。

自製的迭代器

寫一個自己的 loop:

def my_loop
  while true
    yield
  end
end
或者再簡單點:

def my_loop
  yield while true
end
調用它:

my_loop { puts 'my-looping forever!' }
為 my_loop 提供一個代碼塊,方法可以把控制讓給它,當方法把控制讓給代碼塊以後,代碼塊裡的代碼會被運行,完成以後控制又會交還給方法。

剖析方法調用

Ruby 裡的方法調用有幾種形式:

接收者對象或變數

方法名
參數列表(可選,預設是( ) )
代碼塊(可選,無預設)
注意參數列表與代碼塊分別是兩種不同的調用方法的形式。下面這些都是合法的 Ruby 方法調用:

loop { puts 'hi' }
loop() { puts 'hi' }
string.scan(/[^,]+/)
string.scan(/[^,]+/) {|word| puts word}
調用方法時使用代碼塊與不使用代碼塊的區別是,方法是否可以 yield。如果有代碼塊,方法就可以 yield,如果沒有,就不能,因為沒有可以 yield 的東西。

有些方法不管你是不是給它提供一個代碼塊,它都會去做一些事情。比如說 String#split,這個方法會根據你傳遞給它的分割符,去分離它的字串接收者,然後把分離出來的元素放到一個數組裡。但是如果你傳遞給這個方法一個代碼塊,split 會把分離的項目 yield 給一個代碼塊,在代碼塊裡你可以隨便處理每個子字元,可以輸出它,可以把它放到資料庫裡等等。

大括弧與 do/end 代碼塊

do/end ,還有大括弧,使用這兩種形式都可以劃分出一個代碼塊。先做個實驗:

>> array = [1,2,3]
=> [1, 2, 3]
>> array.map {|n| n * 10}
=> [10, 20, 30]
>> array.map do |n| n * 10 end
=> [10, 20, 30]
>> puts array.map {|n| n * 10}
10
20
30
=> nil
>> puts array.map do |n| n * 10 end
#<Enumerator:0x007ff60922ccf0>
=> nil
上面的:

puts array.map {|n| n * 10}
相當於是:

puts(array.map { |n| n * 10 })
上面的:

puts array.map do |n| n * 10 end
相當於是:

puts(array.map) do |n| n * 10 end
使用 do/end 的那個版本,其實就相當於是:

puts array.map
times

times 是 Integer 類的一個執行個體方法,就是你可以整數上調用這個方法。運行代碼塊 n 次,最終返回的值也會是 n 。

在 irb 上試一下:

>> 5.times { puts 'i love u' }
i love u
i love u
i love u
i love u
i love u
=> 5
yielding 給一個代碼塊,從一個方法那裡返回,它們不是一回事兒,上面的 times 可以很好的證明這點。一個方法可以 yield 給它的區塊很多次,從零到無限。但是每個方法在完成它要做的事情以後只能返回一次。比如上面這個例子,輸出了 5 次 i love u ,完成以後返回了一個 5 。

有點像是花樣滑冰,跳起來,在空中做一些旋轉動作,然後落地。不管你在空中轉了多少圈,你只能是跳起來一次,落地也只有一次。方法的調用讓方法運行一次,然後返回一次。但是在它們中間,就像是在空中的旋轉動作,方法可以 yield 控制給代碼塊零次或多次。

>> 5.times { |i| puts "i love u #{i}" }
i love u 0
i love u 1
i love u 2
i love u 3
i love u 4
=> 5
建立一個自己的 times:

class Integer
  def my_times
    c = 0
    until c == self
      yield(c)
      c += 1
    end
  end
end
用一下自己定義的 my_times:

>> 5.my_times {|i| puts "i love u #{i}"}
i love u 0
i love u 1
i love u 2
i love u 3
i love u 4
=> nil
yield 的概念我還是有點模糊,比如這個詞本身的意思,我就有點迷乎,是 “讓出” ?yield 一個值是什麼意思? 是產生一個值?帶來一個值?
each

在一個集合的對象上運行 each 方法,each 會一個一個地 yield 集合裡的每個項目到你的代碼塊裡。

做個簡單的 each 操作實驗:

>> array = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
>> array.each {|e| puts "處理 #{e}"}
處理 1
處理 2
處理 3
處理 4
處理 5
=> [1, 2, 3, 4, 5]
再做一個自己的 each:

class Array
  def my_each
    c = 0
    until c == size
      yield(self[c])
      c += 1
    end
    self
  end
end
用一下:

>> array = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
>> array.my_each {|e| puts "處理 #{e}"}
處理 1
處理 2
處理 3
處理 4
處理 5
=> [1, 2, 3, 4, 5]
下午9:06 **

從 each 到 map

2016年9月10日 上午9:10 **

音樂:《Everything Will Flow》http://music.163.com/#/song?id=28000793

map 一次會處理一個數組的元素同時把它每個元素帶給代碼塊。each 與 map 的區別是,each 返回的值是它的接收者,map 返回的是一個新的數組。這個新的數組的大小跟原來的數組是一樣的,不過新的數組裡的項目是迭代的時候從代碼塊那裡返回來的。

試下 map:

>> names = ["David", "Alan", "Black"]
=> ["David", "Alan", "Black"]
>> names.map {|name| name.upcase }
=> ["DAVID", "ALAN", "BLACK"]
上面得到的結果是一個新的數組,數組裡的每個元素的位置跟原始的數組是一致的,只不過是通過代碼塊處理過的。map 告訴我們,在迭代裡,代碼塊會返回方法交給它的值。這個返回的值會作為調用 yield 的值。

為了實施我們自己的 my_map,我們得先安排一個累加器數組,成功執行了代碼塊返回的值會放到這個數組裡。然後我們再把這個累加器數組作為調用 my_map 的結果。

先來實施一個簡單版本的 map 功能:

class Array
  def my_map
    c = 0
    acc = []
    until c == size
      acc << yield(self[c])
      c += 1
    end
    acc
  end
end
再用一下我們自己定義的 my_map:

>> names = ["David", "Alan", "Black"]
=> ["David", "Alan", "Black"]
>> names.my_map {|name| name.upcase }
=> ["DAVID", "ALAN", "BLACK"]
在 each 的基礎上建立個 map:

class Array
  # Put the definition of my_each here
  def my_map
    acc = []
    my_each {|e| acc << yield(e) }
    acc
  end
end
區塊的參數與變數範圍

代碼塊裡的參數是用豎線包圍的,方法的參數是用括弧封裝的。

先看一個方法:

def args_unleashed(a,b=1,*c,d,e)
  puts '參數:'
  p a,b,c,d,e
end
用代碼塊的方法改裝一下上面的方法:

def block_args_unleashed
  yield(1,2,3,4,5)
end

block_args_unleashed do |a,b=1,*c,d,e|
  puts '參數:'
  p a,b,c,d,e
end
輸出的結果是:

參數:
1
2
[3]
4
5
方法定義會開啟一個新的使用域,代碼塊的範圍有一點點複雜。

做個實驗,看一下代碼塊裡要輸出的 x 是多少:

def block_scope_demo
  x = 100
  1.times do
    puts x
  end
end
執行 block_scope_demo 輸出的結果是 100 。

再做個實驗:

def block_scope_demo_2
  x = 100
  1.times do
    x = 200
  end
  puts x
end
執行 block_scope_demo_2 輸出的結果是 200 。區塊裡面還有外面的 x 是同一個。

再看個例子:

def block_local_parameter
  x = 100
  [1,2,3].each do |x|
    puts "參數 x 是 #{x}"
    x = x + 10
    puts "在區塊裡重新分配 x,現在它是 #{x}"
  end
  puts "在外面 x 仍然是 #{x}"
end
輸出的結果是:

參數 x 是 1
在區塊裡重新分配 x,現在它是 11
參數 x 是 2
在區塊裡重新分配 x,現在它是 12
參數 x 是 3
在區塊裡重新分配 x,現在它是 13
在外面 x 仍然是 100
在區塊內與區塊外不是同一個 x ,因為 x 會作為區塊的一個參數。即使在區塊內重新分配了 x ,但是也不會影響到外面的 x 。也就是你可以在區塊的參數裡使用任何的變數。

有時候你可能希望在區塊裡面使用一些臨時變數,它們也沒有在調用區塊的時候作為參數,你又不想這些在區塊裡影響到外面定義的變數,可以這樣做:

def block_local_variable
  x = '原始 x'
  3.times do |i;x|
    x = i
    puts "在區塊裡 x 現在是 #{x}"
  end
  puts "結束了區塊,現在 x 是 #{x}"
end
結果是:

在區塊裡 x 現在是 0
在區塊裡 x 現在是 1
在區塊裡 x 現在是 2
結束了區塊,現在 x 是 原始 x
一個分號跟著是 x ,表示區塊要使用自己的 x 。分號後面的變數並不是區塊的參數,它們是預留的名字,也就是你想臨時在區塊裡使用的變數,不想影響到外界已經定義了的變數。

上午10:53 ***

處理錯誤

上午10:53 ***

Ruby 在啟動並執行時候如果遇到不能接受的行為就會觸發異常(raising an exception)。

拯救異常

異常是 Exception 類或者它的後代類的一個執行個體對象。觸發異常的意思就是停止執行程式,然後處理遇到的異常或者徹底退出程式。是否處理異常要看你是不是提供了 rescue 。

做個實驗:

ruby -e '1/0'

-e:1:in `/': divided by 0 (ZeroDivisionError)
 from -e:1:in `<main>'
用一個數除以零,出現的異常是 ZeroDivisionError ,它其實是 Exception 的一個後代類。來看一些常見的異常:

RuntimeError:raise 方法觸發的預設的異常。
NoMethodError:調用的方法在對象裡不存在,method_missing 會觸發這個異常。
NameError:解譯器遇到它不懂的標籤符。
IOError:讀取已經關掉的流,讀入唯讀流這些操作。
Errno::error:跟 File I/O 相關。
TypeError:方法收到它不能處理的參數。
ArgumentError:使用的參數的數量有問題。
rescue

遇到異常可以使用 rescue 來拯救。一個 begin 與 end,它們中間是 rescue :

print '輸入一個數字:'
n = gets.to_i

begin
  result = 100 / n
rescue
  puts '沒法弄,你輸入的是 0 嗎?'
  exit
end

puts "100/#{n} 的結果是 #{result}"
執行代碼,如果你輸入一個零,程式會觸發 ZeroDivisionError,我們用 rescue 來拯救,方法就是輸出一條提示資訊,然後退出程式。

上面的例子裡 rescue 的是 StandardError,如果你想拯救個特別的錯誤,可以這樣:

rescue ZeroDivisionError
在方法與代碼塊裡的 rescue

方法與代碼塊裡提供了一個隱式 begin/end 。所以可以這樣:

def open_user_file
  print "要開啟的檔案:"
  filename = gets.chomp
  fh = File.open(filename)
  yield fh
  fh.close
rescue
  puts "不能開啟你想要的檔案!"
end
開啟檔案的操作如果出現了異常,控制會交給 rescue 分句。使用 begin/end 可以更好的來控制要處理的異常:

def open_user_file
  print "要開啟的檔案:"
  filename = gets.chomp
  begin
    fh = File.open(filename)
  rescue
    puts "不能開啟你想要的檔案!"
  end
  yield fh
  fh.close
end
觸發異常

使用 raise 加上你想要觸發的異常的名字。

def fussy_method(x)
  raise ArgumentError, "我需要一個 10 以下的數字" unless x < 10
end

fussy_method(20)
執行的結果是:

demo.rb:2:in `fussy_method': 我需要一個 10 以下的數字 (ArgumentError)
 from demo.rb:5:in `<main>'
rescue 可以像這樣來拯救上面的異常:

begin
  fussy_method(20)
rescue ArgumentError
  puts "不能接受的數字"
end
下面兩行代碼有一樣的效果:

raise "問題!"
raise RuntimeError, "問題!"
在 rescue 裡捕獲異常

把異常對象交給一個變數,可以使用 => 這個操作符,再加上 rescue 命令。異常對象上有一些方法,比如 backtrace 與 message 方法。backtrace 會返回一個數組,裡面表示的是出現異常的時候的調用堆:方法名,檔案名稱,行號。message 方法會返回 raise 提示的資訊。

def fussy_method(x)
  raise ArgumentError, "我需要一個 10 以下的數字" unless x < 10
end

begin
  fussy_method(20)
rescue ArgumentError => e
  puts "這個數字不能接收"
  puts "backtrace:"
  puts e.backtrace
  puts "資訊:"
  puts e.message
end
執行的結果是:

這個數字不能接收
backtrace:
demo.rb:2:in `fussy_method'
demo.rb:6:in `<main>'
資訊:
我需要一個 10 以下的數字
ensure

假如你想讀取一個檔案裡的一行內容,如果這行內容裡沒有找到一個特定的子字串,就觸發一個 ArgumentError 異常,如果找到了就返回這個子字串。但是不管怎麼樣,完成方法以後你都想要關掉檔案的處理。可以這樣做:

def line_from_file(filename, substring)
  fh = File.open(filename)
  begin
    line = fh.gets
    raise ArgumentError unless line.include?(substring)
  rescue
    puts "無效行"
    raise
  ensure
    fh.close
  end
  return line
end
建立自己的異常類

自己的異常類可以繼承 Exception 類:

class MyNewException < Exception
end

raise MyNewException, "出現了新的錯誤!"

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.