当前位置:网站首页 > Ruby编程 > 正文

ruby 编程_编程语法基础知识

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:"Let's go Ruby" 提供了对 Ruby 编程语言的深入探索。Ruby 是一种面向对象的、动态类型的编程语言,以其简洁和优雅的语法以及强大的元编程能力而闻名。本内容通过博客链接、源码分析、工具使用以及实际编程示例,涵盖了 Ruby 的基础语法、编程实践和生态工具应用,旨在帮助读者提升开发效率和代码质量。

1. Ruby语言简介与特点

Ruby是一种动态、反射和面向对象的编程语言,由日本的松本行弘(Yukihiro "Matz" Matsumoto)于1993年开发。Ruby强调语法的简洁和代码的可读性,它是一种解释型语言,意味着代码可以直接执行,不需要编译成机器代码。这种语言以其优雅的语法和强大的灵活性而闻名,被誉为编程中的诗。

在本章中,我们将深入了解Ruby的核心特点,包括它的灵活性、动态类型、丰富的内置库、以及它在Web开发中的流行性。Ruby的广泛库支持和简单的语法让它成为快速原型开发的理想选择,同时,其强大的元编程能力也吸引着那些想要深入语言本质的开发者。

Ruby的一些显著特点包括: - 动态类型 :变量不必显式声明类型,提供了极大的灵活性。 - 干净的语法 :代码易于编写和理解,例如使用 do..end {} 进行代码块的定义。 - 块(Blocks) :Ruby中的块是一种重要的结构,允许你以代码段的形式传递给方法。 - RubyGems :Ruby的包管理系统允许用户安装和管理Ruby库,极大地增强了语言的功能。

接下来的章节将深入探讨Ruby的面向对象编程特性、语法结构、内置功能和扩展库,以及在自动化测试和构建中的应用。

2. 面向对象编程基础

面向对象编程(OOP)是程序设计范式之一,其核心思想是使用对象来表达现实世界的事物和概念。Ruby 作为一种流行的面向对象语言,提供了一系列独特的机制来支持这种范式。

2.1 面向对象的基本概念

2.1.1 类与对象的定义

在 Ruby 中,类是对象的蓝图,是构造对象的模板。每个对象都是某个类的实例,并拥有该类定义的方法和属性。Ruby 中的类使用关键字 class 来定义。

class Person def initialize(name) @name = name end def say_hello puts "Hello, my name is #{@name}" end end # 创建Person类的实例 person = Person.new("Alice") person.say_hello 
  • initialize 方法:在 Ruby 中, initialize 方法用于初始化对象的状态。该方法在新对象创建时自动调用。
  • @name :这是 Ruby 中的一个实例变量。实例变量以 @ 符号开头,它们在对象的所有方法中都是可访问的。
2.1.2 继承、封装、多态的实现

继承允许我们创建一个类来继承另一个类的属性和方法,这有助于代码复用并建立了类之间的层次结构。

class Employee < Person def initialize(name, employee_id) super(name) @employee_id = employee_id end end employee = Employee.new("Bob", "E1234") employee.say_hello puts employee.instance_variable_get(:@employee_id) 
  • Employee < Person :表示 Employee 类继承 Person 类。
  • super(name) :调用了父类 Person initialize 方法,并传递了 name 参数。

封装隐藏了对象内部状态的复杂度,只暴露有限的操作接口,是对象和外界交互的唯一途径。

多态允许我们使用相同的接口访问不同类型的对象,这意味着不同类的对象可以以自己的方式响应相同的调用。

2.2 面向对象的高级特性

2.2.1 模块、混入和单例类

模块在 Ruby 中是一种创建命名空间和代码复用的方式,它们可以被包含(include)在类中,提供了一种形式上的多重继承。

module Greetings def say_goodbye puts "Goodbye" end end class SalesPerson < Person include Greetings end sales_person = SalesPerson.new("Charlie") sales_person.say_hello sales_person.say_goodbye 
  • module Greetings :定义了一个名为 Greetings 的模块。
  • include Greetings :使 SalesPerson 类具有 Greetings 模块中定义的所有方法。
2.2.2 委托模式和元编程

委托模式是一种设计模式,其中一个对象在响应某个调用时,将这个调用委托给另一个对象。

元编程是指编写那些能够改变程序运行时行为的代码,Ruby 中的元编程能力非常强大,允许开发者编写能产生其他代码的代码。

通过 Ruby 的元编程技术,我们可以动态地添加方法和类变量,甚至在运行时修改类的继承结构。这为 Ruby 程序提供了极大的灵活性,但也需要谨慎使用,以免代码变得难以理解和维护。

class User attr_accessor :name, :role def initialize(name) @name = name end end # 动态添加方法 User.class_eval do def role=(new_role) @role = new_role end end user = User.new("Dave") user.role = "Admin" puts user.role 
  • attr_accessor :name, :role :自动为 name role 添加了读写方法。
  • User.class_eval :是一个类方法,它允许我们为 User 类动态地添加或修改方法。

通过 Ruby 的元编程技术,我们可以编写更加灵活和动态的代码,它赋予了 Ruby 程序以巨大的表现力和适应性。然而,这也意味着开发者需要更加关注代码的结构和组织,确保元编程技术不会导致代码混乱和难以维护。

3. Ruby语法与代码结构

3.1 变量、数据类型与运算符

3.1.1 变量的作用域和生命周期

在Ruby中,变量是存储数据的容器,其作用域和生命周期是开发过程中需要特别注意的两个方面。变量的作用域指的是变量能够被访问和使用的代码区域。Ruby中的变量作用域主要分为局部作用域、全局作用域、实例变量作用域以及类变量作用域。

局部变量的作用域限定在定义它们的代码块内部,通常在方法或代码块内部声明。一旦代码执行离开这些区域,局部变量就会被销毁。例如:

def some_method local_var = "I'm local" end puts local_var # => NameError: undefined local variable or method `local_var' 

全局变量以 $ 开头,可以在任何地方访问和修改。例如:

$global_var = "I'm global" def check_global_var puts $global_var end check_global_var # => "I'm global" 

实例变量以 @ 开头,它们的作用域限定在声明它们的类的实例中。实例变量在对象被创建时初始化,并在对象被垃圾回收时销毁。例如:

class MyClass def initialize @instance_var = "I'm instance" end end my_obj = MyClass.new puts my_obj.instance_variable_get(:@instance_var) # => "I'm instance" 

类变量以 @@ 开头,其作用域限定在声明它们的类及其子类中。与实例变量类似,类变量在类被创建时初始化,并在其不再被任何类或对象引用时可能被销毁。例如:

class MyClass @@class_var = "I'm class" def self.read_class_var @@class_var end end puts MyClass.read_class_var # => "I'm class" 

理解变量的作用域对于编写清晰、可维护的代码至关重要。它帮助开发者避免在不合适的地方访问变量,导致程序行为异常或错误。而生命周期管理则涉及到性能优化和资源控制,了解变量何时被创建和销毁有助于编写更高效的Ruby程序。

3.1.2 基本数据类型和运算符的使用

Ruby中的基本数据类型包括数字、字符串、符号、数组和哈希等。每种类型都有一系列的运算符和方法来操作它们。下面将详细介绍这些基本数据类型和它们的运算符。

数字类型

Ruby支持多种数字类型,如整数(Integer)、浮点数(Float)等。运算符包括加(+)、减(-)、乘(*)、除(/)以及取模(%)等:

puts 10 + 20 # => 30 puts 50 - 10 # => 40 puts 4 * 3 # => 12 puts 10.0 / 3 # => 3.* puts 10 % 3 # => 1 
字符串类型

字符串是用单引号或双引号括起来的字符序列。它们之间的主要区别在于双引号字符串会解析变量和转义字符,而单引号字符串则不会。

name = "World" puts "Hello #{name}" # => Hello World puts 'Hello #{name}' # => Hello \#{name} puts 'This is a new line\nThis is not.' # => This is a new line\nThis is not. 

字符串还支持多种操作,如连接(+)、重复(*)、切片等:

puts "Ruby" + "Lang" # => RubyLang puts "Ruby" * 3 # => RubyRubyRuby puts "Ruby"[0, 2] # => Ru 
符号类型

符号(Symbol)是不可变且唯一的字符串值。它们在Ruby内部经常用于提高性能,尤其是在大量使用重复字符串时。符号的使用方式如下:

puts :symbol.class # => Symbol puts :symbol.object_id # => Unique ID of the symbol puts :symbol == :symbol # => true puts :symbol.object_id == :symbol.object_id # => false, since each symbol is unique 
数组类型

数组是有序的元素集合。数组的操作包括索引访问、追加元素、删除元素等:

arr = [1, 2, 3] puts arr[1] # => 2 arr.push(4) puts arr.inspect # => [1, 2, 3, 4] arr.delete(2) puts arr.inspect # => [1, 3, 4] 
哈希类型

哈希是一种将键值对关联起来的数据结构,也被称为字典或关联数组。哈希的操作包括添加、访问、删除键值对等:

hash = { "one" => 1, "two" => 2 } puts hash["one"] # => 1 hash["three"] = 3 puts hash.inspect # => {"one"=>1, "two"=>2, "three"=>3} hash.delete("two") puts hash.inspect # => {"one"=>1, "three"=>3} 

这些基本数据类型及其运算符构成了Ruby编程的骨架。掌握它们,是进行有效Ruby编程的基础。

3.2 控制结构与函数定义

3.2.1 条件判断和循环控制

Ruby提供了丰富的控制结构,以实现逻辑流的控制。这些结构包括 if unless case while until 等。

条件判断

条件判断在Ruby中非常直观,通过 if unless 关键字进行:

number = 10 if number > 10 puts "Number is greater than 10" elsif number == 10 puts "Number is equal to 10" else puts "Number is less than 10" end # unless用法类似于if的否定,通常用在简单的条件判断中 unless number < 5 puts "Number is not less than 5" end 

case 语句提供了多条件分支的便利:

animal = "dog" case animal when "cat" puts "You have a cat" when "dog" puts "You have a dog" else puts "Unknown animal" end 
循环控制

循环控制结构允许你重复执行代码块,直到满足特定条件。Ruby中的循环控制结构有 while until

i = 0 while i < 5 puts i i += 1 end # 等同于 i = 0 until i >= 5 puts i i += 1 end 

Ruby也提供了 loop 方法,通常配合 break 来退出循环:

loop do puts "Press Enter to continue..." break if gets.chomp == "exit" end 

对于迭代数组或哈希,Ruby提供了 each 方法,允许你优雅地遍历集合中的每个元素:

[1, 2, 3, 4, 5].each do |num| puts num end { "one" => 1, "two" => 2 }.each do |key, value| puts "#{key}: #{value}" end 

Ruby的控制结构提供了一种简洁而强大的方式来处理程序中的条件和循环逻辑。通过这些结构,可以编写出既可读又高效的Ruby代码。

3.2.2 函数的定义和参数传递

函数(方法)是Ruby中组织代码和实现代码复用的基本单元。定义函数使用 def 关键字,后跟方法名称和方法体。Ruby的方法可以接受参数,并且有默认参数、可变参数和关键字参数等灵活的参数传递机制。

定义函数
def say_hello(name) puts "Hello #{name}!" end say_hello("World") # => Hello World! 
默认参数
def increment(value=1) value + 1 end puts increment # => 2 puts increment(5) # => 6 
可变参数
def add_values(*numbers) numbers.sum end puts add_values(1, 2, 3) # => 6 
关键字参数
def display_options(options={}) puts options[:message] end display_options(message: "Options are flexible!") 
块(Block)

Ruby中的块是一种可以传递给方法的代码段。块使用 do end 关键字包裹:

3.times do puts "Ruby blocks are awesome" end 

也可以使用花括号 {} 来定义块,尤其是在单行代码中更加简洁:

[1, 2, 3].each { |num| puts num } 

Ruby方法的参数可以有 *args kwargs 形式,允许方法接收不定数量的参数,这提供了极大的灵活性:

def foobar(*args, kwargs) args.each { |arg| puts arg } kwargs.each { |key, value| puts "#{key}: #{value}" } end foobar(1, 2, 3, a: 4, b: 5) 

函数(方法)定义和参数传递是构建复杂功能的基石。灵活使用这些特性,可以让你的Ruby代码更加模块化、可读性和可维护性更强。

4. 常用编程模块和库

随着软件开发的不断深入,Ruby语言的编程模块和库对于提高开发效率和质量起到了至关重要的作用。本章节将详细介绍Ruby的标准库使用以及如何在项目中有效地利用第三方库。

4.1 标准库的使用和功能

Ruby的标准库为开发者提供了一系列功能强大的模块,覆盖了从字符串处理到时间日期管理等多个方面。它们无需额外安装,即可直接使用。

4.1.1 标准库中的字符串处理

字符串在编程中无处不在,Ruby的标准库提供了丰富的字符串处理功能。我们可以通过 String 类的方法来实现字符串的分割、拼接、替换和格式化等操作。

示例代码
# 字符串拼接 first_name = "John" last_name = "Doe" full_name = first_name + " " + last_name puts full_name # => John Doe # 字符串插值 greeting = "Hello, #{full_name}!" puts greeting # => Hello, John Doe! # 字符串替换 text = "I am enjoying learning Ruby." replaced_text = text.gsub("enjoying", "loving") puts replaced_text # => I am loving learning Ruby. # 字符串分割 sentence = "The quick brown fox jumps over the lazy dog" words = sentence.split(" ") puts words # => ["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"] 

在上述代码中,我们展示了字符串拼接、插值、替换和分割的实例。 + 用于直接拼接字符串, #{} 用于插值, gsub 用于全局替换字符串中的字符或子串, split 方法则根据指定的分隔符来拆分字符串。

4.1.2 时间和日期处理方法

时间处理是编程中常见的任务之一,Ruby提供了一整套的时间和日期处理模块,使得时间计算和格式化变得简单明了。

示例代码
require 'date' # 创建日期对象 date = Date.new(2023, 4, 1) puts date.to_s # => "2023-04-01" # 获取当前日期和时间 now = DateTime.now puts now.to_s # => "2023-04-01T00:00:00+00:00" # 时间加减操作 one_hour_from_now = now + 1一个小时 puts one_hour_from_now.to_s # => "2023-04-01T01:00:00+00:00" # 格式化时间 formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") puts formatted_time # => "2023-04-01 00:00:00" 

上述代码展示了Ruby中处理日期和时间的基础方法。我们首先引入了 date 模块,然后创建了一个日期对象并格式化输出。通过 DateTime 类获取当前的日期和时间,并展示了如何进行简单的加减操作。最后,使用 strftime 方法将时间对象格式化为字符串。

4.2 第三方库的选择和应用

随着Ruby社区的蓬勃发展,涌现出了大量优质的第三方库。这些库可以满足开发中的各种特定需求,从Web框架到数据分析工具应有尽有。

4.2.1 常用第三方库的介绍

  • Rails : 一个强大的Web开发框架,让Web应用的开发变得快速和简单。
  • Sinatra : 一个轻量级的Web应用框架,适合创建简单或小型的Web应用。
  • RSpec : 一个行为驱动开发(BDD)的测试框架,用于编写和运行自动化测试。
  • Gems : Ruby的包管理器,用于安装和管理第三方库。

4.2.2 如何在项目中集成和使用第三方库

要在Ruby项目中使用第三方库,通常需要通过 Gemfile 来声明依赖,并通过 bundle install 安装这些依赖。

示例代码
# Gemfile source '*' gem 'rails', '~> 6.0.3' # 指定Rails版本 gem 'rspec-rails' # RSpec测试框架 

在安装了依赖之后,可以通过 require 语句在Ruby文件中引入特定的库。

示例代码
# config/application.rb require 'rails/all' # spec/spec_helper.rb require 'rspec/rails' 

以上步骤说明了如何在Ruby项目中引入和使用第三方库。首先在 Gemfile 中添加依赖,然后通过 bundle install 安装这些依赖。在需要使用这些库的Ruby文件中,使用 require 语句引入相应的模块或库。

这样,我们就能充分利用Ruby社区的力量,为项目增加强大的功能,并提升开发效率。

5. 错误处理和调试

5.1 错误类型和异常处理

在软件开发过程中,错误处理和异常管理是保障程序健壮性和用户满意度的重要环节。Ruby语言提供了丰富的错误类型和异常处理机制,让开发者能够优雅地处理各种运行时问题。

5.1.1 Ruby中的错误类型

在Ruby中,错误可以大致分为两类: StandardError ArgumentError StandardError 是大多数异常的基类,常见的如 TypeError NameError 等都继承自它。 ArgumentError 则通常用于参数错误的情况。

以下是一个简单的例子,展示如何抛出和捕获 StandardError 类型的异常:

def risky_operation raise StandardError, "Something went wrong!" end begin risky_operation rescue StandardError => e puts e.message # 输出错误信息 end 

此外,Ruby还有 SystemExit SignalException 等预定义异常类型,它们在特定的系统事件发生时会被抛出。

5.1.2 使用rescue进行异常处理

在Ruby中,使用 begin...rescue...end 块来进行异常处理是一种非常常见的做法。 rescue 关键字后面跟上异常类型和变量,表示捕获该类型的异常。如果在 begin 块中抛出该类型的异常,那么异常会被 rescue 块捕获。

begin risky_code rescue StandardError => error # 这里可以记录错误信息或者进行错误回滚等操作 handle_error(error) else # 如果没有异常发生,执行这里的代码 puts "No errors occurred" ensure # 无论是否发生异常,都会执行这里的代码 cleanup_resources end 

ensure 关键字后跟的代码块会在 begin-rescue 块执行完毕后无条件执行,这通常用于清理资源,如关闭文件句柄、释放锁等。

5.1.3 自定义异常

开发者还可以根据需要定义自己的异常类型。自定义异常可以继承自 StandardError 或其他异常类,并且可以在异常处理逻辑中通过特定的异常类型来处理特定的错误情况。

class CustomError < StandardError; end def raise_custom_error raise CustomError, "A custom error has occurred." end begin raise_custom_error rescue CustomError => e puts "Caught a custom error: #{e.message}" end 

自定义异常使得错误处理更加清晰和具体,有助于提高代码的可读性和维护性。

5.2 调试技巧和工具

为了快速定位问题并提高开发效率,Ruby开发者需要掌握一系列调试技巧和使用高效的调试工具。

5.2.1 常用的调试命令和技巧

在Ruby中,有几种常用的调试技术可以迅速定位问题所在:

  1. 使用 p 方法或 puts 打印变量值,帮助了解程序运行时的状态。
  2. 使用 binding.pry byebug 来暂停代码执行,并进入交互式的调试环境。
  3. 使用 Kernel#trace_var 来跟踪变量的改变。
  4. 使用 raise 抛出异常,配合 rescue 捕获并处理,或者直接终止程序。

例如,利用 byebug 进行代码调试:

require 'byebug' def debug_example a = 1 b = 0 byebug # 在这里代码会暂停执行 c = a / b puts "This line won't be reached" end debug_example 

程序执行到这里会进入 byebug 的调试环境,在这里可以逐行执行代码,查看变量状态,甚至修改变量值以测试不同的代码路径。

5.2.2 调试工具的使用和选择

Ruby的标准库和第三方提供了多种调试工具,可以根据不同的需求来选择。

  1. IRB (Interactive Ruby) :Ruby自带的交互式命令行界面,可以测试代码片段。
  2. Pry :比IRB更强大和灵活的交互式调试环境,支持插件。
  3. RubyMine :IntelliJ IDEA的Ruby版本,提供一个功能强大的集成开发环境,内置调试工具。
  4. Visual Studio Code :一个轻量级代码编辑器,支持Ruby语言扩展,可以集成调试工具进行断点调试。

选择合适的调试工具可以帮助开发者快速定位和解决问题,提高开发效率。每种工具都有其特点和适用场景,建议根据个人喜好和项目需求进行选择。

总结

错误处理和调试是软件开发中的重要环节,Ruby提供了丰富的功能和工具来帮助开发者应对这一挑战。通过理解错误类型、掌握异常处理的技巧、使用调试命令和工具,开发人员能够确保应用程序的稳定性和健壮性。下一节我们将探讨如何在Ruby中进行自动化测试和构建工具的使用。

6. 自动化测试和构建工具使用

6.1 测试框架的选择和使用

6.1.1 RSpec测试框架介绍

RSpec是一个非常流行的行为驱动开发(BDD)测试框架,它专注于软件行为的描述。它允许开发人员通过编写可读性强的测试用例来描述软件的行为。RSpec为Ruby提供了丰富的工具集,使得测试代码和生产代码分离,提高了测试的可读性和可维护性。

要开始使用RSpec,首先需要确保已经安装了RSpec gem。可以通过以下命令安装:

gem install rspec 

安装完成后,可以通过 rspec --init 命令生成一个基本的配置文件 spec_helper.rb ,这个文件用于初始化RSpec的环境。

6.1.2 测试用例的编写和执行

编写RSpec测试用例通常遵循这样的结构: describe 块描述一个行为的集合, it 块则具体描述了一个行为(即一个测试用例)。下面是一个简单的例子:

RSpec.describe 'String' do describe '#reverse' do it 'returns the reversed string' do expect('Ruby'.reverse).to eq('ybuR') end end end 

上面的例子中, describe '#reverse' 表示正在测试字符串对象的 reverse 方法。 it 'returns the reversed string' 则具体描述了测试的内容。 expect('Ruby'.reverse).to eq('ybuR') 是断言表达式,用来验证 reverse 方法的输出是否符合预期。

要运行这个测试用例,只需在命令行中输入 rspec ,RSpec会自动发现并执行当前目录下所有的测试文件。

6.2 构建工具的配置和应用

6.2.1 Bundler的使用和gemfile配置

Bundler是一个用于管理Ruby应用程序依赖关系的工具,它与Gemfile一起工作,后者是一个声明式文件,描述了你的应用程序需要哪些gem依赖。

创建一个Gemfile并添加所需的gem:

source '*' gem 'rspec', '~> 3.0' 

然后在命令行中运行 bundle install ,Bundler会根据Gemfile中的依赖关系安装相应的gem,并将它们锁定在Gemfile.lock文件中,以确保其他开发人员在安装时获得相同版本的依赖。

6.2.2 自动化构建脚本的编写

编写自动化构建脚本是为了简化软件编译、测试、打包等一系列过程。Ruby中,可以使用Rake来编写构建脚本,Rake是Ruby的一个构建工具,它允许定义任务和子任务。

下面是一个基本的Rakefile示例:

require 'rake' task :default => :spec desc 'Run all RSpec tests' task :spec => 'spec' 

在这个例子中,定义了一个默认任务 default ,它依赖于 :spec 任务。 :spec 任务描述了运行所有RSpec测试的任务。当运行 rake 命令时,将会执行所有的RSpec测试。

要创建一个更复杂的构建过程,比如编译、测试和打包,可以创建多个任务,并用Rake的依赖机制将它们链接起来:

desc 'Build the application' task :build => [:compile, :test, :package] desc 'Compile source files' task :compile do # 编译过程 end desc 'Run test suite' task :test => :compile do # 运行测试 end desc 'Package application' task :package => :test do # 打包过程 end 

在这个结构中, :build 任务会触发编译、测试和打包一系列任务,而这些任务都是依赖于彼此的。这样的构建脚本不仅可以自动化整个构建过程,而且可以清晰地定义每个步骤,方便团队协作和项目维护。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:"Let's go Ruby" 提供了对 Ruby 编程语言的深入探索。Ruby 是一种面向对象的、动态类型的编程语言,以其简洁和优雅的语法以及强大的元编程能力而闻名。本内容通过博客链接、源码分析、工具使用以及实际编程示例,涵盖了 Ruby 的基础语法、编程实践和生态工具应用,旨在帮助读者提升开发效率和代码质量。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

到此这篇ruby 编程_编程语法基础知识的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • Ruby 网络编程2024-11-14 12:09:08
  • ruby 写文件_怎样发送电子邮件到别人邮箱里2024-11-14 12:09:08
  • Ruby 元编程_编程语言2024-11-14 12:09:08
  • Ruby学习笔记(1)2024-11-14 12:09:08
  • ruby编程实践实验室报告_创意实验室编程2024-11-14 12:09:08
  • ruby 编程_编程的基础知识2024-11-14 12:09:08
  • ruby 程序_python简单编程2024-11-14 12:09:08
  • 初探Ruby编程语言2024-11-14 12:09:08
  • 尝试ruby编程2024-11-14 12:09:08
  • ruby语言适合做什么_编程语言有哪些2024-11-14 12:09:08
  • 全屏图片