句柄表和继承

句柄表和继承

句柄代表着备操作的对象

句柄的本质(handler)

句柄表可以看做一个非常大的结构体数组
句柄表的结构

索引值: 进程通过索引找到句柄表中对应的选项
内核对象地址: 通过地址直接找到对应的内核对象
访问掩码: 控制了访问权限
标志位: 标志改句柄能否被继承

ListView控件

ListView控件 实现简单进程管理

用到的相关api函数

//获取控件句柄
HWND GetDlgItem(
        HWND hDlg,//获得控件所处的窗口的句柄
        int nIDDlgItem //控件id
);
//初始化列表的列 (listview插入新的一列
int ListView_InsertColumn(
    HWNDhwnd, //控件的句柄
    int iCol,  //第几列 (索引 index
    const LPLVCOLUMNpcol //结构体指针 (包含新列的结构体
);
//插入新的一行条目
int ListView_InsertItem(
        HWND hwnd,
        const LPLVITEM pitem
);
//设置条目的属性
BOOL ListView_SetItem(
        HWND hwnd,
        const LPLVITEM pitem
);
//删除所有项目
BOOL ListView_DeleteAllItems(
        HWND hwnd
);
//标准输出格式化字符串
swprintf(buffer,L"%s,哈哈",param);
//清空
ZeroMemory(buffer);

list属性:

进程的遍历、获取与销毁

进程的遍历、获取与销毁

创建快照遍历

//获得进程所使用的堆,模块和线程的信息快照
HANDLE WINAPI CreateToolhelp32Snapshot
(
        DWORD dwFlags,//标志位
        DWORD th32ProcessID //进程ID
)
//dwFlags: 指定的快照中,指定需要拍的系统部分
TH32CS_INHERIT          声明快照句柄是可继承的。
TH32CS_SNAPALL          在快照中包含系统中所有的 进程和线程。
TH32CS_SNAPHEAPLIST     在快照中包含ID所指定的进程的所有的堆。
TH32CS_SNAPMODULE       在快照中包含在ID所指定的进程的所有的模块。
TH32CS_SNAPPROCESS      在快照中包含系统中所有的进程。
TH32CS_SNAPTHREAD       在快照中包含系统中所有的线程。
BOOL WINAPI Process32First(
    HANDLE   hSnapshot,     //快照句柄  
    LPPROCESSENTRY32 lppe    //获得的信息
);获得快照中的第一个成员的信息
BOOL WINAPI Process32Next(
    HANDLE   hSnapshot,       //快照句柄
    LPPROCESSENTRY32 lppe    //获得的信息
);获得快照中后一个成员的信息

函数实现

进程的创建

进程的创建

进程的启动过程

  1. 打开目标exe的映象文件
  2. 创建进程内核对象
  3. 映射NTDLL到内存
  4. 创建线程内核对象
  5. 通知子系统对进程进行管理
  6. 启动线程初始化空间和加载其他DLL
  7. 跳转到入口处开始执行

CreateProcess api

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information
  LPPROCESS_INFORMATION lpProcessInformation // process information
);
//中文版注释
BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // 可执行模块名称 (全路径 必须是const字符串
  LPTSTR lpCommandLine,                      // 命令行(字符串 可以不是const字符串
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // 进程安全描述符
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 线程描述符
  BOOL bInheritHandles,                      // 继承标志位
  DWORD dwCreationFlags,                     // 创建标志位 (指定控制优先级和创建过程的额外标志,除了如前说,可以在任何组合中指定下列创建标标志
  LPVOID lpEnvironment,                      // 进程环境块
  LPCTSTR lpCurrentDirectory,                // 驱动目录
  LPSTARTUPINFO lpStartupInfo,               // 启动信息 指向一个窗体结构,该接口体表示新进程的窗口应该如何出现
  LPPROCESS_INFORMATION lpProcessInformation // 进程信息
);
//启动信息参数的结构体
typedef struct _STARTUPINFO {
    DWORD   cb;     //记录指定结构体大小,以字节为单位
    LPTSTR  lpReserved;
    LPTSTR  lpDesktop;
    LPTSTR  lpTitle;  //对于控制台进程,日过创建了新的控制欲窗口,则会显示标题栏中的标题,如果NULL。可执行文件额名称将会用作窗口标题, This parameter must be NULL for GUI or console processes that do not create a new console window.
    DWORD   dwX;  //控制窗口位置x
    DWORD   dwY;  //控制窗口位置y
    DWORD   dwXSize; //控制窗口宽度
    DWORD   dwYSize; //控制窗口高度
    DWORD   dwXCountChars;
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;
    DWORD   dwFlags;
    WORD    wShowWindow; //窗口显示方式
    WORD    cbReserved2;
    LPBYTE  lpReserved2;
    HANDLE  hStdInput;
    HANDLE  hStdOutput;
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
//进程信息结构体
typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess; //进程句柄
    HANDLE hThread;  //主线程句柄
    DWORD dwProcessId; //被创建的进程id
    DWORD dwThreadId; //被创建的主线程ID
} PROCESS_INFORMATION;

exp: 启动qq

进程和线程

进程和线程

什么是进程?

进程和普通计算机程序的区别

  • 进程 是运行中的程序
  • 进程 活在内存中 有血有肉有灵魂
  • 程序 死在 硬盘上的 有肉没血没灵魂

如果进程是空间的概念,那么这段空间里有什么?

窗口与事件

窗口与事件

窗口

什么是窗口?

Windows中称为视窗,是一个程序的操作显示界面

窗口执行动作是由什么驱动的?

Windows中通过什么机制将发生的一些动作和响应的响应函数连接起来

API与宽字符

API与宽字符

API(Application Programming Interface,应用程序编程接口)

Api的定义

api就是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或者硬件的一访问一组例程的能力,而又无需访问源码,或者理解内部工作机制的细节

win32中的宽字符

win32中的宽字符

宽字符

数据类型容器、模板
ASCII一个字符一个字节
GB码(扩展了的ASCII)英文字符一个字节
GB码中文字符两个字节
UNICODE字符集(unicode编码实际指的是utf-16)常用字符两个字节

宽字符: 用多个字节来表示的字符称之为宽字符(只要不是以单字节存储都可称为宽字符)

unicode和utf8编码

兼容问题

由于ASCII存在字符含量过少的缺陷,所以不但我国自己搞出了国际码。其他国家也都设计出了符合自己国情的字符集

Cpp9 模板

模板

下面是一个针对int的冒泡排序

// _20180301.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
void Sort(int* arr,int nLength)
{
    int i,k;
    for (i = 0;ix > base.x && this->y > base.y;
    }
private:
    int x;
    int y;
};
template
void Sort(T* arr,int nLength)
{
    int i,k;
    for (i = 0;iy)
            return x;
        else
            return y;
    }
    M min()
    {

Cpp8 运算符重载和深浅拷贝

深浅拷贝

相同类型间可以直接拷贝

// _20180212.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
class A
{
private:
    int* a;
public:
    A()
    {
        a = new int[10];
    }
    virtual ~A()
    {
        delete a;
        printf("析构 A \n");
    }
};
int main(int argc,char* argv[])
{
    A a1;
    A a2;
    a1 = a2;
    return 0;
}
//反汇编
27:       A a1;
0040108D   lea         ecx,[ebp-14h]
00401090   call        @ILT+15(B::B) (00401014)
00401095   mov         dword ptr [ebp-4],0
28:       A a2;
0040109C   lea         ecx,[ebp-1Ch]
0040109F   call        @ILT+15(B::B) (00401014)
004010A4   mov         byte ptr [ebp-4],1
29:       a1 = a2;
004010A8   lea         eax,[ebp-1Ch]
004010AB   push        eax              //a2 作为参数传递
004010AC   lea         ecx,[ebp-14h]    //a1 作为this指针传递
004010AF   call        @ILT+45(A::operator=) (00401032)
30:       return 0;
A::operator=:
004012E0   push        ebp
004012E1   mov         ebp,esp
004012E3   sub         esp,44h
004012E6   push        ebx
004012E7   push        esi
004012E8   push        edi
004012E9   push        ecx
004012EA   lea         edi,[ebp-44h]
004012ED   mov         ecx,11h
004012F2   mov         eax,0CCCCCCCCh
004012F7   rep stos    dword ptr [edi]
004012F9   pop         ecx
//eax = a1首地址
004012FA   mov         dword ptr [ebp-4],ecx
004012FD   mov         eax,dword ptr [ebp-4]
//ecx = a2首地址
00401300   mov         ecx,dword ptr [ebp+8]
//ecx + 4 这里是 class A中变量a的地址(ecx 对应虚表地址)
//因为ecx是变量a2 所以这里的edx = a2.a
00401303   mov         edx,dword ptr [ecx+4]
//a2.a 赋值给a1.a
00401306   mov         dword ptr [eax+4],edx
//返回a1首地址
00401309   mov         eax,dword ptr [ebp-4]
0040130C   pop         edi
0040130D   pop         esi
0040130E   pop         ebx
0040130F   mov         esp,ebp
00401311   pop         ebp
00401312   ret         4

我们发现使用=直接赋值对象,编译器自动生成了operator= 函数用于处理类型赋值
我们观察编译器自动生成的函数operator=,这里赋值直接略过了虚表(ecx+4)

Ruby11 拾遗

Agenda

  1. Loop
  2. Expression
  3. File Read/Write
  4. Debug
  5. Process & Thread

Loop

while

a = 10
while a > 0
  puts a
  a -= 1
end

until

a = 100
until a == 0
  puts a
  a -= 1
end

loop

a = 10
loop do
  break if a  0

!~ 正则匹配 是否匹配不到 匹配到返回fals 匹配不到返回true

Ruby10 Class Module Gem 深入

Agenda

  1. class_eval & instance_eval
  2. method_missing
  3. Module as a namespace
  4. Gems
  5. require vs load
  6. $LOAD_PATH

class_eval

  1. 首先class_eval是只有类才能调用的,Class#class_eval
  2. class_eval会重新打开当前类的作用域
# class_eval
class User
end
User.class_eval do
  attr_accessor :name
  def hello
    "hello"
  end
end
user = User.new
user.name = "world"
puts user.name
puts user.hello


# module"s self
module Management
  def self.track
    "track"
  end
end
class User
  include Management
end
# User.track # => error
Management.track


# class_eval in project
# requirement: we need to execute a class method when module included
module Manegement
  def self.included base #Manafement模块被其他类Included的时候会执行
    base.extend ClassMethods #User类注入ClassMethod
    base.class_eval do #打开User类
      setup_attribute
    end
  end
 # Manegement 内部模块 当引入Management的时候 会被引用为其他类的类方法
  module ClassMethods
    def setup_attribute
      puts "setup_attribute"
    end
  end
end
class User
  include Manegement #目的是在include Management 的时候执行一些方法或者设置
end

instance_eval

  1. instance_eval 是所有类实例的方法
  2. 打开的是当前实例作用域
# instance_eval, instance methods and class methods
# 1. as a question
class User
end
User.class_eval do
  def hello
    "hello"
  end
end
User.instance_eval do
  def hi
    "hi"
  end
end
puts User.hi
user = User.new
puts user.hello
# puts user.hi #报错

# instance_eval, singleton_method
a = "xxx"
a.instance_eval do
  def to_hello
    self.replace("hello")
  end
end
puts a.to_hello
# b = "world"
# b.to_hello # => error

# class_eval as instance_eval
class User
end
User.class_eval do
  def hello
    "hello"
  end
  # works same as instance_eval
  def self.hi
    "hi"
  end
end
puts User.new.hello
puts User.hi

method_missing

  1. 当当前作用域上下文没有找到方法时就会调用
  2. method_missing方法
# metho missing
#
# 1. how it works
# 2. ancestors
# 3. rails"s AR
class User
  def hello
    "hello from User"
  end
  def method_missing(name, *args)
    "method name is #{name} ,parameters :#{args}"
  end
end
user = User.new
puts user.hello
puts "-" * 30
puts user.hi("hello",19)

Namespace

  1. Module
  2. Class
  3. Constants

使用::来访问

Ruby9 Class & Modules 进阶

Ruby的内部类结构

Array.class # => Class
Class.class # => Class

superclass 查看父类

Array.superclass # =>Object
Object.superclass # =>BasicObject
BasicObject.superclass # => nil

ancestors 查看当前类的继承链

Array.ancestors # => [Array, Enumerable, Object, Kernel, BasicObject]

Method Finding 方法查找

# class structure, method finding
class User
  def panels
    @panels ||= ["Profile", "Products"]
  end
end
class Admin < User
end
puts Admin.ancestors
admin = Admin.new
p admin.panels
# 从下往上查找 在admin中查找 找不到往上找User 然后Object 然后Kernel 然后 BasicObject

Method Overwrite 方法覆盖

  1. class和module可以重新打开
  2. 方法可以重定义
# 重新打开class
class User
  def panels
    @panels ||= ["Profile", "Products"]
  end
end
class User
  def panels
    "overwrite"
  end
end
puts User.ancestors
admin = User.new
p admin.panels
# 从下往上查找 在admin中查找 找不到往上找User 然后Object 然后Kernel 然后 BasicObject

# overwrite and re-open
class Array
  def to_hello_word
    "hello #{self.join(", ")}"
  end
end
a = %w[cat horse dog]
puts a.to_hello_word

# overwrite and re-open
a = %w[cat horse dog]
puts a.join(",")
class Array
  def join
    "hello"
  end
end
puts "-" * 30
puts a.join

Module

Array.ancestors # => [Array, Enumerable, Object, Kernel, BasicObject]
Enumerable.class # => Module
Module.class # => Class

# module acts linke a class
module Management
  def company_notifies
    "company_notifies from management"
  end
end
class User
  include Management
  def company_notifies
    puts super
    "company_notifies from user"
  end
end
p User.ancestors
puts "-" * 30
user = User.new
puts user.company_notifies

# module included sequence
module Management
  def company_notifies
    "company_notifies from management"
  end
end
module Track
  def company_notifies
    "company_notifies from track"
  end
end
class User
  include Management
  include Track
  def company_notifies
    puts super
    "company_notifies from user"
  end
end
p User.ancestors
puts "-" * 30
user = User.new
puts user.company_notifies

# 1 module included in module
# 2 module acts as class
module Management
  def company_notifies
    "company_notifies from management"
  end
end
module Track
  include Management
  def company_notifies
    puts super
    "company_notifies from track"
  end
end
p Track.ancestors
puts "-" * 30
include Track
puts company_notifies

# module"s class method
module Management
  def self.progress
    "progress"
  end
  # you need to include/extend/prepend to use this metod
  def company_notifies
    "company_notifies from management"
  end
end
puts Management.progress

include vs prepend

  1. include 把模块注入当前类的继承链(祖先链) 后面
  2. prepend 把模块注入当前累的继承链(祖先链) 前面
# module include
# include
module Management
  def company_notifies
    "company_notifies from management"
  end
end
class User
  prepend Management
  # include Management
  def company_notifies
    "company_notifies from user"
  end
end
p User.ancestors
puts "-" * 30
user = User.new
puts user.company_notifies

include和exten方法

当模块被include时会被执行,同事会传递当前作用于的self对象

Ruby8 继承(Inheritance)和模块(Modules)

继承示例

# inheritance
class User
  attr_accessor :name, :age
  def initialize name, age
    @name, @age = name, age
  end
  def panels
    # ||= 操作符, 如果变量不存在 那么就赋值
    @panels ||= ["Profile", "Products"]
  end
end
class Admin < User
  def panels
    @panels ||= ["Profile", "Products", "Manage Users", "System Setup"]
  end
end
user = User.new("user_1", 18)
p user.panels
puts "-" * 30
admin = Admin.new("admin_1", 28)
puts admin.name
p admin.panels
# 查看这个类的父类
p Admin.superclass

常用關鍵字

super关键字
调用父类的同名方法
self關鍵字
指向當前作用域實例

Ruby7 OOP

Everything is Object 一切皆对象

1
2
3
4
5
6
7

    a = "hello"
    a.class # => String
    b = 3.14
    b.class # => Float
    c = %w[pear cat horse]
    c.class # => Array

Instance Method & Instance Attribute 实例方法,实例属性

  1. Instance Method: 实例方法,成员方法,成员函数
  2. Instance Attribute: 实例变量,成员属性,属性(property),使用@定义
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    # class
    class User
      def initialize name, age
        @name = name
        @age = age
      end
      # getter
      def name
        @name
      end
      def age
        @age
      end
    end
    user = User.new("Hello", 18)
    puts user.name
    puts user.age

    # class
    class User
      def initialize name, age
        @name = name
        @age = age
      end
      # getter
      def name
        @name
      end
      def age
        @age
      end
      # setter
      def name= name
        @name = name
      end
      def age= age
        @age = age
      end
    end
    user = User.new("Hello", 18)
    puts user.name
    puts user.age
    puts "-" * 30
    user.name = "hello 2"
    user.age = 20
    puts user.name
    puts user.age
    

    # class, attr_reader, attr_writer
    class User
      attr_reader :name
      attr_reader :age
      attr_writer :name
      attr_writer :age
      def initialize name, age
        @name = name
        @age = age
      end
    end
    user = User.new("Hello", 18)
    puts user.name
    puts user.age
    puts "-" * 30
    user.name = "hello 2"
    user.age = 20
    puts user.name
    puts user.age
    

    # class, method
    class User
      attr_accessor :name
      attr_accessor :age
      def initialize name, age
        @name = name
        @age = age
      end
      def say_hi
        puts "hello  #{@name}, i am #{@age}"
      end
    end
    user = User.new("Hello", 18)
    user.say_hi

Class Method & Class Variable 类方法,类变量

  1. Class Method:类方法,静态方法
  2. Class Variable:类变量, 使用@@定义
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    # class, method
    class User
      attr_accessor :name
      attr_accessor :age
      @@counter = 0
      def initialize name, age
        @name = name
        @age = age
        @@counter += 1
      end
      def say_hi
        puts "hello  #{@name}, i am #{@age}"
      end
      def self.get_counter
        @@counter
      end
    end
    puts User.get_counter
    user = User.new("Hello", 18)
    user.say_hi
    puts User.get_counter

## Access Control 访问控制

  1. public
  2. protected
  3. private

    # class, method
    class User
      attr_accessor :name
      attr_accessor :age
      def initialize name, age
        @name = name
        @age = age
      end
      def say_hello
        puts "hello..."
        say_hi
        say_hey
      end
      def say_hi
        puts "hello  #{@name}, i am #{@age}"
      end
      def say_hey
        puts "hey, i am #{@name}"
      end
      protected :say_hi, :say_hey
    end
    user = User.new("Hello", 18)
    user.say_hello

Dynamic Ruby 动态特性

User内幕

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    # attr_accessor 方法从哪里来的?
    class User
      # ...
    end
    User.class # => class
    # Class.attr_accessor 背后的秘密
    # define_method
    # attr_accessor, define_method
    define_method :hello do
      puts "hello world"
    end
    hello

自己实现 attr_accessor

Ruby6 细节补充

代码规范

  1. 使用UTF-8编码
  2. 使用空格缩进,不使用tab, 1 tab = 2 spaces
  3. 不需要使用分号(;)和反斜杠()连接代码

Demo

Ruby5 其他的奇技淫巧

变量赋值

# 变量交换
a = 1
b = 2
b,a = a,b
puts a
puts b
puts "-" * 30
x = [1, 2, 3]
a, b = x #默认会把数组中的值依次赋值给 a ,b
puts a
puts b
puts "-" * 30
x = [1, 2, 3]
a, *b = x #这里a会接受第一个元素 b用了*号 表示接受剩下所有的元素
puts a
p b
#output
2
1
------------------------------
1
2
------------------------------
1
[2, 3]

Fixnum & Float

# number
puts 1 / 10
puts 1 / 10.0
puts "-" * 30
#output
0.1
------------------------------

String

# string
a = "world"
b = %Q{
    hello
    #{a}
}
# 这里不但可以用 {} 也可以用 ()
# 但是这里的Q必须是大Q 如果是小q的话 就相当于单引号的效果
puts b
puts "-" * 30

Ruby4 Blocks and Exceptions

Block 代码块

  1. Block是一个参数
  2. 匿名参数
  3. Callback
  4. 使用do/en或者{}来定义
{puts "hello"}

Demo:

# block usage
def hello
    puts "hello method start"
    yield
    yield
    puts "hello method end"
end
hello {puts "i am in block"}
#output
hello method start
i am in block
i am in block
hello method end


# yield with parameter
def hello
    puts "hello method start"
    yield("hello","world")
    puts "hello method end"
end
hello {|x,y| puts "i am in block,#{x} #{y}"}
#output
hello method start
i am in block,hello world
hello method end

# yield with paramter
def hello name
    puts "hello method start"
    result = "hello " + name
    yield(result)
    puts "hello method end"
end
hello("world"){|x| puts "i am in block,i got #{x}"}
#output
hello method start
i am in block,i got hello world
hello method end

# build in methods
["cat", "dog","frog"].each do |animal|
    puts animal
end
puts "-" * 30
["cat","dog","frog"].each{|animal| puts animal}
#output
cat
dog
frog
------------------------------
cat
dog
frog


# build in methods
10.times do |t|
    puts t
end
puts "-" * 30
("a".."d").each { |char| puts char}
#output
1
2
3
4
5
6
7
8
9
------------------------------
a
b
c
d

# varibale scope
# before ruby2.0
x = 1
[1, 2, 3].each { |x| puts x}
puts x # => x will be 3,which is incorrect
#output
1
2
3
1
如果是在ruby2之前的版本 那么外部的变量x会被改变

# varibale scope
# 如果是2.0版本之后 puts x会报错
sum = 0
[1, 2, 3].each { |x| sum += x}
puts sum
# puts x
#output
6

# block return value
class Array
    def find
        each do |value|
            return value if yield (value)
        end
        nil
    end
end
puts [1, 2, 3].find { |x| x == 2 }
#output
2

# block as named parameter
def hello name, &block
    puts "hello #{name}, from method"
    block.call(name)
end
hello("world") {|x| puts "hello #{x} form block"}
#output
hello world, from method
hello world form block

# yield with parameter
def hello
    puts "hello method start"
    yield("hello","world")
    puts "hello method end"
end
hello {|x,y| puts "i am block ,#{x},#{y}"}
#output
hello method start
i am block ,hello,world
hello method end

# block_given?
def hello
    if block_given?
        yield
    else
        puts "hello from method"
    end
end
hello
puts "-" * 30
hello {puts "hello from block"}
#output
hello from method
------------------------------
hello from block

# block can be closure
def counter
    sum = 0
    # 代码库接收了一个参数x 如果x没有定义那么x为1 然后 sum +=x
    proc {|x| x = 1 unless x; sum +=x }
end
c2 = counter
puts c2.call(1) #1
puts c2.call(2)
puts c2.call(3)
# 这里 closure 为闭包
#
#output
1
3
6

# new method to create block
# name is required
hello = -> (name){"hello #{name}"}
puts hello.call("world")
puts "-" * 30
# name is required
hello3 = lambda {|name| "hello #{name}"}
puts hello3.call("world")
puts "-" * 30
hello2 = proc {|name| "hello #{name}"}
puts hello2.call
puts hello2.call("world")
# lambda和proc区别 proc可以不传参数 lambda 更像是一个方法,必须传递参数
#output
hello world
------------------------------
hello world
------------------------------
hello
hello world

Exceptions 异常

All Exception inherited from Exception Class