Io语言简单入门

本文记录了《七周七语言》的读书笔记和在IoLanguageGuide的一些内容。

Io语言同Lua、JavaScript一样是一种原型语言,每个对象都是另一个对象的复制品。

核心优势:拥有大量可定制语法和函数,以及强有力的并发模型。
Io没有关键字,Io语法只不过是把消息全部串联起来,每条消息都会返回一个对象,每条消息也都带有置于括号内的可选参数。在Io中,万事万物都是消息。
被复制的对象就叫做原型
原型语言,每个对象都不是类的复制品,而是一个实实在在的对象。

Io> "Hi ho, Io" print
发送print消息给字符串"Hi ho, Io",接受者(对象)在左边,消息在右边。
Io不区分类和对象,可以通过复制现有对象创建新对象,现有对象就是原型。
Vehicle := Object clone
对象带有槽(slot),相当于可以为每个对象绑定一个散列表。
使用:= 可以初始化槽并赋值,使用=可以给槽赋值。
Io惯例:类型应以大写字母开头。
对象是槽的容器。发送槽名给对象就可以获得该槽,如果该槽不存在,则调用父对象的槽。
在Ruby和Java中,类是创建对象的模板。在Io中,bruce := Person clone,bruce和Person都是对象。Person还是类型,因为它有type槽。除此之外,它们完全相同。
方法(method())也是对象。可以把它赋给一个槽。
Lobby是主命名空间,包含了所有的已命名对象。
原型编程范型的基本原则:
   所有事物都是对象; 
   所有与对象的交互都是消息; 
   你要做的不是实例化类,而是复制那些叫做原型的对象;  
   对象会记住它的原型; 
   对象有槽; 
   槽包含对象(包括方法对象); 
   消息返回槽中的值,或调用槽中的方法; 
   如果对象无法响应某消息,则它会把该消息发送给自己的原型。 

集合:list 和 map
     toDos := list("a","b","c)
     list(1,2,3,5) average
     elvis := Map clone
     elvis atPut("home","Graceland")
     elvis size
布尔值:和Ruby一样,0是true。只有nil和false是false。且true,false,nil都是单例。
单例:Single := Object clone 
          Single clone := Single

Io有三种赋值运算符:


operator     action
::=          Creates slot, creates setter, assigns value
:=           Creates slot, assigns value
=            Assigns value to slot if it exists, otherwise raises exception

第二天
条件和循环
分号会把两个不同的消息连接起来。
while循环带有一个条件和一个用来求值的消息。
     while(i <= 11,i println ; i = i+1);"This one goes up to 11" println
for循环带有一个计数器、一个初始值、一个终止值、一个可选的增量、以及一个带发送者的消息:
     for(i,1,11,i println);"goes up to 11" println
     for(i,1,11,2,i println);"goes up to 11" println # 2为增量,每次增加2
Io允许额外参数。    for(i,1,11,i println,"extra args");
if:if(condition,true code ,false code)
if(condition) then(true code) else (false code)
运算符
像面向对象语言一样,很多原型语言也在运算符上用到了语法糖。如"+"和"/"
查看运算符表:
     OperatorTable
OperatorTable addOperator("xor",11) 
为布尔值增加xor方法:
true xor := method(bool,if(bool,false,true))
false xor := method(bool,if(bool,true,false))
消息:
     Io代码中除了注释符和参数之外的逗号外一切都是消息。
     一个消息由三部分组成:发送者、目标和参数。在Io中,消息由发送者发送至目标,然后由目标执行该消息。
      call方法可以访问任何消息的元消息。


Lobby 打印已经存在的对象
print 打印Lobby的内容
检查对象:
1 获得对象的槽列表:
Io>    someObject slotNames
2 排序显示上表:
someObject slotNames sort
3 slotSummary以整洁方式展示槽名
4 观察方法未编译的版本:
     获取一个Block的值而不启动它
     Lobby getSlot("forward")
5 在交互模式运行io脚本:
     doFile("scriptName.io")
   如果想在某个对象的上下文中执行则:someObject doFile("scriptName.io")
   doString : 计算一个字符串
   someObject doString("1+1")  
6 命令行参数:
    System args 
     打印附加的命令行参数:System args foreach(k,v,write("'",v,"'\n"))
7 launchPath
     System launchPath 槽是源文件最初执行的路径,是当前工作路径。

句法:
Io没有关键字和声明语句。一切都是由消息构成的表达式,每个消息都是一个运行期可访问的对象。
(for,if等看起来的关键字其实都是消息)
BNF描述:(用于描述语言的语法)
exp        ::= { message | terminator }
message    ::= symbol [arguments]
arguments  ::= "(" [exp [ { "," exp } ]] ")"
symbol     ::= identifier | number | string
terminator ::= "\n" | ";"
消息参数被当做表达式传递,并由接收者计算。
运算符:一个运算符只是一个名字没有字母的消息或or,and,return中的一个。
赋值:::= 建槽,建setter,赋值
          :=  建槽,赋值
          =   赋值

source compiles to
a ::= 1 newSlot("a", 1)
a := 1 setSlot("a", 1)
a = 1 updateSlot("a", 1)
数值:
          123
123.456
0.456
.456
123e-4
123e4
123.456e-7
123.456e2
Hex numbers are also supported (in any casing):
0x0
0x0F
0XeE
字符串:
     带转义字符的 "str\n" or 
     不带转义,且可多行输入的
     s := """this is a "test".
     This is only a test.""" 
注释:
     // , /**/ , #

对象:
     在Io中,一切皆对象,所有的动作都是消息。对象由一个包含许多键值(槽)的列表和一个继承自原型的内置列表构成。槽的key是一个符号(一个不可变字符串),value可以是任何类型的对象。
clone和init:
     新的对象都是通过复制已有对象创建的。 clone完成后将会调用init槽(如果有的话)。
继承:
     对象收到消息-> 消息符合该对象的某个槽,执行
                        ->  找不到槽,循环向上找该对象的原型 
     Io命名空间没有全局变量, 根对象被称为Lobby
     Dog := Object clone 
     把Lobby的槽"Dog"设置成一个对象的复制。
方法:
     方法就是一中匿名函数,调用的时候创建一个对象储存本地变量,并设置本地原型指针和自己的槽到消息目标上。
     用method
     一般形式:(最后一个是方法体,其它的是方法参数)
     method(<arg name 0>, <arg name 1>, ..., <do message>)

代码块:
     Blocks vs. Methods:
     共同点:被调用时都创建对象来保存本地变量。
     不同点:method中"proto"和"self"被设置到消息对象的目标上。block中"proto"和"self"它们都被设置到创建时的本地对象上。所以一次失败的变量查找,将引起在代码块创建上下文的本地变量中继续查找,而方法则是在消息接收者中继续查找。
     eg.
     b := block(a,b,a+b)
     m := method(a,b,a+b)
     b -> block...
     m -> exception ...
     当一个本地对象被创建,它的self槽被设置(到:method:消息目标,block:创建的上下文中),call槽被设置为一个Call对象,用来访问block信息:
slot               returns
call sender         locals object of caller
call message      message used to call this method/block
call activated      the activated method/block
call slotContext   context in which slot was found
call target          current object
以上的槽在某个消息中使用,可以通过反射获得消息的信息
protos : 返回一个对象的继承列表
code : 返回以个方法的字符串表达式
子对象方法体; resend
super(原型方法名)
code : view source

控制流:
IF:
if(<condition>, <do message>, <else do message>)
     if(y < 10, x := y, x := 0) 
is the same as:
     x := if(y < 10, y, 0)
Like SmallTalk (ifTrue ,ifFalse,ifNil,ifNonNil:
     (y < 10) ifTrue(x := y) ifFalse(x := 2)
if(y < 10) then(x := y) elseif(y == 11) then(x := 0) else(x := 2)

LOOP:     
3 repeat("foo" print) ==> foofoofoo 
while
Arguments:
while(<condition>, <do message>)
for(<counter>, <start>, <end>, <optional step>, <do message>)
break,continue :
loop, repeat, while and for support the break and continue methods. Example:
for(i, 1, 10,  if(i == 3, continue) if(i == 7, break) i print )
return :立即返回
import

并发:
协程Coroutines:Io使用用户级协程代替抢占式的系统级线程来实现并发,避免了大量的开销。
Scheduler:用于恢复挂起的协程。先进先出策略。
Actors:拥有自己的异步消息队列的对象。
     Io里的每个对象都可以发送异步消息,asyncSend() 返回nil,futureSend()返回future
     当一个对象收到一个异步消息时,它将消息放到它的队列里,如果没有队列,就开启一个协程处理队列里的消息。已经排队的消息依序被处理。可以使用yield将控制权转移给其他的协程。
Futures:当结果就绪时,future就会成为结果。允许程序最小化阻塞,同时去除了管理同步的细节。
     自动死锁检测 通过检查已连接的future,发现死锁,抛出异常。
     future会等待处理完成
     命令行会试图打印结果。所以如果结果是一个future,就会等待future结果。
     q := method(wait(1)) 
     futureSend(q) # delay 1-second
     futureSend(q);nil # no delay nil是结果
Yield:对象在处理它的消息间隙会自动yield。yield会把控制权转移给其他协程。
resume and pause

异常:
raise:通过在一个异常原型上调用raise()触发异常。
try and catch:
     try() 方法返回在它内部发生的异常,若没有就返回nil
     e := try(<doMessage>)
     catch()方法返回:不匹配->异常;匹配->nil
     e := try(
        //...
     )
     e catch(Exception,
          writeln(e coroutine backtraceString)
     )
pass:传递异常到上层处理类,通常在所有catch之后
e := try(
    // ...

e catch(Error,
    // ...
) catch(Exception,
    // ...
) pass     
自定义异常:复制已有异常:
     MyErrorType := Error clone


基本类型:
     基本类型是内建在Io中,方法由C实现并且在实例中隐藏了某些数据的对象。所有的基本类型都继承自Object,且都是可变的。
      问号?可以判断是否存在某槽:
     obj ?foo 相当于 if(obj getSlot("foo"),obj foo)
List:支持数组和枚举操作
     append(obj)
     size
     at(index)
     atPut(index,obj)
     atInsert(index,obj)
     remove(obj)
     ...
foreach:
     foreach,map,select方法有三种用法:
     a := list(25,123,12)
     一:a foreach(index,value,write(index,":",value,","))
     第一个参数是索引,第二个参数是值,第三个参数是每个值要计算的表达式
     二:a foreach(v,v println)
     去除索引参数
     三:a foreach(println)
     去掉索引和值参数,仅把表达式作为消息发送给每个迭代的值。
map和select:(我觉得最好翻译成映射和过滤)
     select相当于其他语言的filter
     map和select的使用方法与foreach无异。
     map和select都会返回新的list
序列Sequence:     
     不可变序列称为Symbol,可变序列称为缓冲Buffer或字符串String。字面量(在源码中被引号引起的)是Symbol。通过调用 asMutable方法可获得Symbol的可变复制体。
     size
     containsSeq(str) # 是否包含字符串
     at(n) # 获得第n个位置的字符(比特)
     slice(start,end) # java.lang.String#substring(start,end) 
          slice(-n) # 获取最后n个字符
          slice(start,-end) # 返回去除最后end个字符的字符串
     asUppercase
     asLowercase
     split # 默认按空格分隔字符,返回list
          split("") # 按指定字符分隔返回list
     asNumber
     interpolate # 重新计算#{}中的值,#{}中可以是任意代码,但是必须返回能响应asString方法的对象 name := "Bflee" ; "My name is #{name}" interpolate
    
Range:一个保存了开始、结束端和如何开始到结束的容器。常用于创建大型有序数据组成的列表,以及作为for方法的替代。

File:
     获取代表file的对象:
     f := File with("foo.txt")
     f remove // 删除
     f openForUpdating 
     f openForAppending
     f openForReading
     f write("")
     f close
Directory:
     dir := Directory with("/Users/bflee/")
     files := dir files // 列出某目录的所有文件list
     items := Directory items // 列出文件夹和文件list
     items at(4) name 
     Directory items map(name) // 列出当前目录所有文件夹和文件名
     Direcotry items select(? isDirectory not) map(name) // 列出当前文件夹内所有文件的文件名
     Direcotry items select(? isDirecotry not) select(name containsSeq("bak") not) map(name) sort // 列出当前目录所有不包含bak的文件名。
     root := Directory clone setPath("C:/")  // 获取一个指向特定路径的目录
     root fileNames // 获取文件列表
     root exists // 测试是否存在
     Directory currentWorkingDirectory // 获取当前工作路径 同 System launchPath
Date:
     d := Date clone     
     d now // 设置为当前日期/时间
     Date now asNumber // 获取当前日期/时间,以秒表示
     Date now year/month/day/hour/minute/second      
     Date cpuSecondsToRun(100000 repeat(1+1)) // 测试代码执行时间
     
XML:
     # Using the XML parser to find the links in a web page:
     SGML // reference this to load the SGML addon
     xml := URL with("http://www.yahoo.com/") fetch asXML
     links := xml elementsWithName("a") map(attributes at("href"))


转载于:https://my.oschina.net/bfleeee/blog/100999

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值