經過例子和實踐來學習rho語言。下面的例子和練習都很值得去運行、閱讀、修改和完善。修改練習和教程中任何你感到有意思的代碼,這樣可以得到最好的學習效果。該教程包含了rho語言最多見以及最重要的特性,足以讓開發者快速入門。node
課程0 -- 開發環境程序員
配置你的開發環境web
爲了能夠運行這個教程裏面的rholang代碼,你須要一些開發環境。 這不是一個會讓你感到疲憊的rholang開發工具或者技術棧。 然而它展現了一些基本的開發環境給你開始。編程
網上編譯器瀏覽器
RChain社區的成員提供了一個基於公共網站的在線rholang編譯器。 這個工具很是有前途,也是一種入門的簡單方式。 可是它仍是開發節點,有時候會不穩定。app
本地節點編程語言
真正正確運行rholang代碼的方法是在經過啓動你本身本地機子的RNode而後使用它的rholang編譯器。 首先你要爲你本身的平臺安裝 RNode工具
對於初學者,這裏有詳細的一步一步指導你怎麼使用AWS 或者Docker啓動你的節點.oop
一旦你的RNode安裝好了,你能夠運行基本的獨立節點。學習
$ rnode run -s -n
在單獨的終端裏,你能夠在REPL模式下一次執行一行rholang。
$ rnode repl
╦═╗┌─┐┬ ┬┌─┐┬┌┐┌ ╔╗╔┌─┐┌┬┐┌─┐ ╦═╗╔═╗╔═╗╦
╠╦╝│ ├─┤├─┤││││ ║║║│ │ ││├┤ ╠╦╝║╣ ╠═╝║
╩╚═└─┘┴ ┴┴ ┴┴┘└┘ ╝╚╝└─┘─┴┘└─┘ ╩╚═╚═╝╩ ╩═╝
rholang $ Nil
Deployment cost: CostAccount(0,Cost(0))
Storage Contents:
for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }
rholang $ @"world"!("hello")
Deployment cost: CostAccount(5,Cost(64))
Storage Contents:
@{"world"}!("hello") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }
當你運行更多行數的rholang代碼時候,你可使用RNode的eval模式來執行代碼。
$ rnode eval intersection.rho
Evaluating from intersection.rho
Result for intersection.rho:
Deployment cost: CostAccount(39,Cost(1132))
Storage Contents:
@{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)}!(@{"name"}!(Nil)) | @{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)}!(@{"age"}!(Nil)) | @{"world"}!("hello") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( @{{@{"name"}!() | _ /\ @{"age"}!() | _}} <= @{Unforgeable(0xb19519ab773d1ec4ce96f1b71b748552e4a084dfc9942371717f5cb87e818879)} ) { @{Unforgeable(0x00)}!("Both name and age were in the data") } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }
有一些RNode的輸出會出如今你運行代碼的同一個終端。可是其它一些代碼輸出會直接出如今第一個終端。 因此在你熟悉什麼輸出出如今哪裏前請肯定好檢查兩邊的終端。
Cryptofex IDE
一個叫作cryptofex 的開發環境已經進入了alpha版本。 Cryptofex可能最後最好的開發rholang的地方,可是如今仍是很早期的軟件。 Cryptofex提供rholang語法高亮特性而且能夠在RChain集成節點上檢測dApps。 IDE同時也提供環境建立和測試在以太網上,私人測試網上和單獨模式的EVM上的智能合約。
課程1 -- 發送與標準輸出(stdout)
發送與標準輸出(stdout)
說聲Hello
"Person waiving hello"
編程界有一個存在已久的傳統——輸出"Hello World"應該是你學習的第一個程序。下面是一個在屏幕上輸出"Hello World"的最簡單例子。
hello.rho
練習
請讓程序輸出"Rholang rocks!" 而不是 "Hello World"。
練習
嘗試將"stdout"替換爲別的語句。會獲得什麼結果?
嘗試一下這個有趣的通道名稱@"someChannel". 這裏能夠比較隨意。請讓程序在屏幕上輸出 "Sup World"。
標準輸出(stdout)究竟是什麼東西
Channels are like mailboxes for sending messages
rho語言的核心是通道(channel,下面都稱爲通道)通訊. 通道是你能夠用來發送和接收消息的通訊線路。你可使用!字符來在通道中發送消息。
Redo this diagram!
stdout 是一個特殊的通道,用於將文本發送至"標準輸出",一般指你的電腦屏幕。正由於它的特殊,咱們不得不將它寫在第一段學習的代碼裏面。
使用其餘通道
Sent messages wait to be received here in "message purgatory"... JK, it's called the "tuplespace"
實際上你能夠在不少通道中發送消息,而非只有stdout。 但其它通道不像 stdout 他們不會在屏幕上顯示。
tupleSpace.rho
那麼,在其餘通道中的消息將被髮送至哪裏?哪裏都不會去!這些消息暫時哪兒都不去,這些消息會繼續待在通道內,等待其餘人去取出它們。咱們將在下一課程中學習如何獲取這些消息。同時,消息滯留所在的地方,咱們稱爲 "元組空間"。
請確保你的信息保留在元組空間裏。你應該會看到像下面的信息。
Storage Contents:
@{"RandoChannel"}!("This won't be on the screen") | for( x0, x1 <= @{Unforgeable(0x01)} ) { Nil } | for( x0, x1, x2, x3 <= @{"secp256k1Verify"} ) { Nil } | for( x0, x1 <= @{"sha256Hash"} ) { Nil } | for( x0, x1 <= @{Unforgeable(0x03)} ) { Nil } | for( x0, x1, x2, x3 <= @{"ed25519Verify"} ) { Nil } | for( x0, x1 <= @{"blake2b256Hash"} ) { Nil } | for( x0 <= @{Unforgeable(0x02)} ) { Nil } | for( x0 <= @{Unforgeable(0x00)} ) { Nil } | for( x0, x1 <= @{"keccak256Hash"} ) { Nil }
同時作兩件事
Rather than following an ordered list, all ingredients are added concurrently. Looks delicions
在rholang中,咱們不會告訴計算機作完一件事,再到另外一件。相反,咱們會告訴它須要作的全部事情,而後"並行地"執行它們,或者一次性所有執行。
parallel.rho
| 的發音是 "parallel", 可簡稱爲 "par"。
練習
向"pizza shop"通道發送消息"1 large pepperoni please"。
練習
向"Mom's Phone"通道發送"Hi Mom"。
練習
用一個程序在屏幕上輸出兩個消息,"Rick"和 "Morty"。
小測試
stdout!("Programming!") 將在屏幕上輸出什麼?
Programming!
stdout!
Nothing
@"what"!("Up") 在什麼通道上發送消息?
@"Up"
@"what"
what
rholang會先執行哪一條語句?
@"stdout"!("Dogs")
|
@"stdout"!("Cats")
輸出 "Dogs"
輸出 "Cats"
都不。 它們是並行的 PS. 有一個特殊的通道 stderr. 請嘗試一下看看往這個通道發送消息,會發生什麼? 有什麼區別?
課程2 -- 接收
消息檢查
// Dear future self, keys in freezer because...
在上一章咱們學習瞭如何發送消息。如今是時候學習如何接收消息了。常規語法以下:
for(message <- channel){ // Do something here}
順便提一下, // 用於標示註釋。 //後面的內容程序並不會運行。寫好註釋能夠有利於其餘開發者(包括你本身)閱讀代碼,並瞭解代碼的意圖,其餘讀你代碼的開發者會感激你寫註釋的。
通訊事件
Pizza shop can receive messages on its channel.
下面的代碼使用披薩店的通道發送了一個消息,披薩店收到了它。pizza店經過將消息打印至標準輸出來代表其已收到。
pizzaOrder
練習
將上述消息發送至一個不一樣的通道,如@"coffeShop". 消息會被接收端打印出來嗎? 仍是東西留在了元組空間裏麼?
Let's hit up the coffee shop.
練習
記住,在rholang中,任何事情都是並行地而非按順序地執行。若是咱們把接收信息的代碼放在前面,那麼披薩店的代碼仍可執行。嘗試一下吧。
元組空間污染
若是你遇到了舊數據滯留在元組空間並會對後面的代碼執行有影響,你須要清空你的元組空間。最簡單的方式是刪除你的數據目錄.rnode
使用上述方法清空元組空間已通過時了。一個更好的方法是防止它一開始被舊數據污染。咱們能夠經過修改最上面的new代碼段來實現。
舊的方案
new stdout(rho:io:stdout
) in { @"world"!("Welcome to RChain") }
嘗試下面新的方案
new world, stdout(rho:io:stdout
) in { world!("Welcome to RChain") // No more @ or " " }
咱們將在「不可僞造的names」的課程中講解它的原理。如今你不須要每次都重置通道。
發送前接收
Rather than the message appearing first, then someone receiving it, Greg is trying to receive first. Hopefully someone will send him a message so he can have a comm event.
當發送和接收同時存在於通道時,這被稱爲通訊事件,或稱爲"comm event"。
不像普通郵件那樣必須被髮送,對方纔能被接收,在rholang中,上述兩個事件能夠以任何順序發生或者同時發生。這相似於能夠先接收消息,再發送它。每當發送和接收共存時,就會觸發通訊事件。
合約
The poor chef is too busy making sure he can receive orders to take care of his pizza.
咱們的披薩店例子很好地說明了通訊事件,但指望每次有新的訂單時,披薩店都能自動發出一個新的接收來處理它們,這並不現實。
幸運地是,咱們能夠只部署一次代碼,而後每次接收到它的消息時都執行一次。這類代碼稱爲「智能合約」。讓咱們看一個比披薩店更高級但類似的例子--咖啡店。
coffeeShop.rho
練習
在咖啡店點第二杯飲料
練習
更改上面例子的確認消息
通常來講,下列哪個會第一個發生?
發送,由於它與普通郵件的工做原理同樣。 接收,由於以該方式運行的代碼更快。 發送或接收均可以最早發生,或者同時。 接收,由於rohlang是並行的。 都不。直接觸發通訊事件(comm event)。
練習
通道被命名爲 @"coffeeShop"。將它改名爲你所選擇的特定咖啡店的名稱。而後使用咱們最近學到的new來修改代碼
Persistent For
實際上,在rholang中有兩種不一樣的語法來表示持續從通道取出信息。咱們剛剛學習contract語法。下面的用for語法的代碼是等價的。
contract @"coffeeShop"(order) = { for(order <= @"coffeeShop") { 注意,上述代碼與正常的 for 不一樣,由於它使用了雙劃線 <= 而不是單劃線 <-. for和contract是有不一樣的地方的,咱們會在討論區塊鏈的時候討論到他們的區別。如今你能夠將它們當作同一功能。
練習
用持久的for語法而不是"contract"語法來寫一個想咖啡店這樣的披薩店合約。嘗試本身從頭寫一次整個代碼,這樣會讓你更容易記清語法。
下面哪一項是與其餘兩項不一樣的?
for (a <- b){}
contract b(a) = {}
for (a <= b){}
哪個發送語句會與for (message <- @"grandmasSnapChat"){Nil}對應產生一個通訊事件 ?
grandmasSnapChat!("Hi Grandma")
@"grandmasSnapChat"!("Glad you're snapping Grandma")
for("Here's a snap for you g'ma" <- @"grandmasSnapChat")
課程3 -- 傳音筒、"name"和「process」
消息傳遞
The game of telephone is perfect to simulate message forwarding in rholang.
在前面的章節,咱們學習瞭如何向祖母或披薩店發送消息。可是至今全部的接收方都經過將消息打印至標準輸出,來告知已經接收到了。
如今讓咱們作一些更有意思的事情--相似孩子們的傳話遊戲那樣傳遞消息。
telephone3.rho
你能夠經過運行上面的代碼來作實驗。你能夠修改你以爲合適的地方多運行幾回。
練習
傳話遊戲頗有趣,但有更多玩家參與會更好。請添加第三位明教Charlie的玩家。bob接收消息後將發送消息給Charlie,而不是簡單打印至stdout。而後Charlie將它打印至屏幕上。多多益善!
The message never seems to get there correctly. I blame Bob.
練習
若是你曾經玩過電話遊戲,你應該知道,消息極少能被正確地傳遞。Bob如今決定經過發送一條錯誤的消息。改寫程序,使得Bob不管收到什麼,都能傳遞不一樣的消息。
*這究竟是啥?
Opposites attract
你注意到 @"Bob"!(message)中的? 在rholang中有兩種類型, "names" 和 "processes"。一樣也有能夠在二者之間互相轉化的方法。
"processes"能夠是rholang中任何一個代碼片斷,例如咱們的傳話筒遊戲,或者是披薩店訂單程序。「process」能夠是上百行的大程序,也能夠只有幾行。它們甚至能夠是用於表示值的代碼。下面是一些「process」的例子。
stdout!("Sup Rholang?") 一個常見的發送操做。
Nil 最小的「process」。如字面意思,它不作任何事。
for(msg <- @"phone"){Nil} 一個常見的接收操做,在消息到達時它不會作任何事。
"Hello World" 另外一個不作任何事請的小「process」。被稱爲"基礎術語"。 "names"能夠被用於賦名通道以發送消息。在大多數編程語言中,"name"是徹底獨立的同樣東西,它們自己就存在。可是在rholang中,"name"來自"引用process",即將@標籤放在「process」以前,便可獲得一個"name"。下面是"name"的一些例子。
@"Hello World" 經過引用基礎術語"Hello World"來建立。
@Nil 最小的「name」。經過引用最小的「process」來建立。
@(@"Alice"!("I like rholang, pass it on."))
經過引用來自傳話筒遊戲的"process"來建立。
關於*的一切
What kind of name is that!? Did your parents just name you after some computer code?
經過用@符號來標記「process」,咱們能夠將「process」打包以建立一些「name」。咱們也能夠經過使用*標記「name」,從而將「name」轉變爲「process」。
在rholang中,咱們須要記住的是發送「process」和接收「name」。這很重要,所以我再次強調。你老是發送一個「process」,在另外一端接收一個「name」。
Aice經過for(message <- @"Alice")接收咱們的消息,因此, message 變成了一個「name」。當她以後發送給Bob時,她不得不發送「process」,因此她要用@"Bob"!(message)使用將message轉變回一個「process」。
小測驗
咱們發送什麼?
processes
names
咱們接收什麼?
processes
names
@"registration"是什麼?
process
name
非法語法
Nil是什麼?
process
name
非法語法
@Nil是什麼?
process
name
非法語法
@@Nil是什麼?
process
name
非法語法
*importantData 是一個「process」, 那麼importantData是什麼?
process
name
非法語法
下面哪個與"BobsPhone"等價?
*@"BobsPhone"
@"BobsPhone"
*"BobsPhone"
@*BobsPhone
stdout!("BobsPhone")
練習
This telephone game has a fork
不像以前的線性傳話遊戲那樣,每一個玩家將信息傳遞給下一位,我麼來爲遊戲添加一個分支。如今,Bob與先前同樣將發送消息給Charlie,但同時也會發送給Elise。
每一個分支的長度由你定,但在每一個分支的最後都得將消息打印至標準輸出。
課程4 -- 持續發送與窺探
爲何要重複發送?
This radio navigation aid helps airplanes navigate by broadcasting the same message over and over
咱們的披薩和咖啡店均可以在同一個複用通道中接收消息。咱們使用一個持續的for (msg <= chan){...}或者一個合約contract chan(msg){...}來達成這一目的。
空中交通管制塔樓可能會樂於作恰好相反的事——不停地發送相同的消息。塔樓中的控制者但願記錄同時包含天氣和跑道信息的消息,而且提供給全部須要的飛行員。相似披薩店, 他們很繁忙,不會費力地在每次飛行員須要時都不停地發送信息。
持續發送的語法
控制塔須要在代碼上作較小的調整,以使得發送操做可以持續。他們會使用!!而非單個!。
persistentSend.rho
請自行確認一下,原先發送的消息是否仍然在元組空間內。
練習
注意上述代碼,第二名飛行員一樣可以接收到信息。發送仍在持續。
對了,你注意到了嗎?當咱們實際上並不使用stdout時,咱們不須要new stdout(...) in {}
for (x <- y) {Nil} | y!!(Nil)中有多少次通訊事件發生?
1
不少次
0
二次檢查消息
正如咱們剛纔展現的,持續性發送和接收很是有用。可是,普通的發送和接收也一樣足夠好了。設想這樣的場景:我將一個字母發送給祖母,她接收到了這個消息。
grandma.rho
如今咱們設想:我想要二次檢查我是否給她發送了正確的時間。我能夠簡單地取出這條消息,但這樣一來她就無法讀取這個消息了。
練習
依據你所知道的,你能夠經過獲取這個消息,自行檢查它,再將它發送回舊的通道,以達到咱們的目的。
請自行嘗試上面的方案。答案已列在下面。
for (x <= y) {Nil} | y!!(Nil)會產生多少個通訊事件?
1
不少個
0
答案
grandmaCheck.rho
窺探語法
Maybe I'll just peak at Grandma's letter through the envelope.
rholang之後會爲觀察通道內變量提供一個特殊的語法。目前咱們還不能使用它,可是下面會展現給你看這個語法的用法。咱們將使用<!操做符來"窺探"一個通道內的消息。
peek.rho
若是你使用過excel的宏,或者excel,你應該對如何在不取出數據的狀況下訪問它感到很是熟悉。把它當作for (value <! A1) { ... }。
下列哪個語法是用於窺探一個消息的?
for (x <! y){...}
for (x <= y){...}
x!!(y)
for (x <! y) {Nil} | y!!(Nil)會產生多少個通訊事件?
1
許多
0
課程5 -- Join操做
多數據源
In general, the winner of this pushup competition can't be determined until both participants are finished.
有時候僅當從兩個以上不一樣的數據源獲取數據後,纔會開始計算。例如,在你得知了你的彩票號碼和中獎號碼以前,你沒法知道你是否贏得大獎。在你知道購買物品價格和購買總額以前,你沒法進行購買。在你知道每一個參賽者作了多少個俯臥撐前,你沒法知道誰贏得俯臥撐比賽。
rholang提供了Join操做,來應對這種狀況。使用;符號來執行一次Join操做。
for (p1Pushups <- @"player1"; p2Pushups <- @"player2") { @"stdout"!("The winner is...") }
火箭發射
一家太空探索公司想要確保,僅當兩個航空工程師,Alice和Bob,都下達了發射命令後,他們的火箭纔會發射。例如,Bob將經過發送BobLaunch!("launch")來下達命令。當兩位工程師都下達了命令,那麼火箭即可以發射。
練習
思考一下,使用咱們剛提到的Join操做符,應該怎麼寫這個代碼呢?
錯誤的方式
下面的例子中,其中一人先收到發射指令,並嘗試處理火箭發射問題,而後再輪到另外一我的。
launchBad.rho
問題在於,當Alice批准發射,而Bob尚未,Alice應該可以更改她的指令,但在此例中她不行。設想一下,若是她忽然發覺火箭有一個問題,或者收到了一些很差的消息,想要中止發射。
No use in grabbing just one set of mail. Might as well wait until the second set
當使用Join時,她依然能夠更改她的決定,由於for只會在雙方的消息都進入通道並準備好後,纔會開始取出雙方的消息。
發射的解決方案
launch.rho
下列哪一段代碼是Alice所需,用以撤銷發射命令的?
@"AliceCancel"!("cancelZ")
@"AliceLaunch"!("cancel")
for (x <- @"AliceLaunch"){Nil}
Join的概念起初是在哲學家進餐問題中被提出,而且在這篇簡短的rholang教程中(更詳細的解釋)[developer.rchain.coop/tutorial/#d…"]。
在for (x <- y; a <- b){ Nil }中, 應該優先向哪個通道發送消息?
y
b
無所謂
同時被髮送
在for (x <- y; a <- b){ Nil }中, 哪一條消息被優先取出?
x
a
無所謂
會被同時取出
練習
有一個比賽,兩名選手將各自在各自的通道發送消息。誰第一個發送了消息,誰就輸掉比 賽,第二個發送消息的人獲勝。你的任務是寫一段代碼告訴咱們誰贏了。參賽選手應按以下方式發送消息。
P1!("Send any message") P2!("Hope I win")
在這場須要靠耐心獲勝競賽這一例子中,咱們不使用求並運算,由於咱們在乎哪一個選手先行動。但願你沒有陷入個人陷阱中;)
patienceSolution.rho
正如註釋所說,你應該使用REPL模式運行上面的代碼,而後用兩種不一樣的順序來發送的消息確保兩個選手都獲勝一次。另外一個方案以下所示,讓一個玩家去通知另外一個玩傢什麼時候執行。咱們將在下一節繼續研究這種方法。
P1First.rho
在上面咱們寫的代碼中,爲何可能出現沒有人贏得這場耐心比賽?
由於兩名選手能夠同時發送消息
選手們在錯誤的通道發送消息
第一個塊接收P2,而第二個塊接收P1,因此代碼並不能保證遊戲完成
課程6 -- 不可僞造的Names和Acks
使通道"私有"
A competing pizza shop steals orders because the channel isn't secure.
到目前爲止,每個咱們發送信息的通道都是公共的"name",如@"pizzaShop"。 任何一我的均可以往這個通道發送信息(可能對於某些商用行爲是好的),可是任何一我的也能夠從這個通道中獲取信息(這對於一些商業就很糟糕了)。想象一下若是競爭者能夠從披薩店中獲取他們的披薩訂單讓披薩店沒法獲取他們的訂單,那確定十分糟糕。
披薩店的競爭者須要什麼樣的代碼來竊取披薩點的訂單?
contract evilPizzaShop(interceptedMessage) = {Nil}
@"evilPizzaShop"!("pizzaShop")
@"pizzaShop"!("intercept")
for (interceptedMessage <- @"pizzaShop"){...}
綁定和自由的Names
上面咱們學習到如何經過for和contract獲取信息。這兩種方式都構造出"綁定的"「names」。舉個下面例子,order就是在咖啡店代碼裏一個綁定的"name"。
bound1.rho
當咱們使用contract語法的時候也是同樣的。
bound2.rho
若是一個"name"存在在一個特定的"process"中而且不能被"process"外部訪問,咱們就認爲一個"name"是綁定的。因此"name" order是綁定在咖啡代碼中。另外一方面,在上面的例子中,任何一個能從別的地方訪問的"name"都是"自由的"「name」。在上面的例子中,@"coffeeShop" 是一個自由的"name"。
指出下面每段代碼中 x 是綁定的仍是自由的。
for (x <- y){Nil}
綁定的
自由的
都不是
for (y <- x){Nil}
綁定的
自由的
都不是
new x in { x!(true) }
綁定的
自由的
都不是
contract x(y) = { Nil }
綁定的
自由的
都不是
contract y(x) = { Nil }
綁定的
自由的
都不是
for (y <- @"x"){Nil}
綁定的
自由的
都不是
new操做符
for 和 contract都是在連續計算中綁定"name"的完美方法。可是若是咱們想要建立一個綁定的"name"用於發送? 舉個例子,咱們的披薩店不想讓本身的訂單被人截取。咱們經過new操做符解決這個問題。
newPizzaShop.rho
首先要注意到 pizzaShop 是一個"name"即便它不是以 @開始。
那是由於new操做符直接把它創造爲一個"name"而不是一個引號括起的"process"。不管你如何使用new創造一個"name", 它老是一個綁定的"name"。
而後,注意這種方法不只能夠阻止其它披薩店獲取訂單,還阻止新的客戶下訂單。咱們將會在bundles教程中解決這個問題。
當你在new 限制範圍外嘗試下訂單會發生什麼事情。
訂單正常發送
訂單正常發送可是須要更長時間
出現關於頂層自由變量的錯誤
代碼能夠運行,可是沒有訂單成功被接受不了
咱們學習到全部的"name"能夠經過用@標記轉化爲"process"。因此 pizzaShop這個"name"經過@轉化後是一個什麼樣的"process"? 嘗試將那個"process"打印到stdout 看看。
@標記的"pizzaShop"
並無任何標記
"一些不能夠僞造的16進制代碼"
私有 vs 不可僞造
Although the messages can no longer be stolen, they can still be eavesdropped on. You've been warned.
new 是一個限制操做符由於它把本身建立的綁定的"names"限制在它的花擴話中或者說"詞法範圍"內. 在rholang的世界裏,這些新建的"names"就只能在肯定的範圍內可見,可是記住,程序員能夠從外部世界中查找到這些"names"。當你在區塊鏈環境工做中尤爲要注意。
因此說,雖然競爭的披薩店再也不可能竊取 原本給咱們店的披薩訂單,可是他們仍然能夠在區塊鏈瀏覽器中知道咱們這些訂單的信息。有些狀況下,一些程序員會把new 建立的"names"稱爲 "私有的", 可是一個更恰當的詞應該是 "不可僞造的(unforgeable)", 這就能解釋前面的問題了。
咱們前面用到了 new 來阻止元組空間被污染. 爲何使用不可僞造的"names"可讓咱們避免每一個合約跑以前都清理一次元組空間?
由於 new 建立自由的"names"
由於 new 建立出不可僞造的"names",它們不能被外部代碼使用
由於 new 自動清理元組空間
確認通道
We acknowledge communications all the time in conversations
不可僞造"names"一個通用的用法就是 "確認通道", 簡稱爲"ack" 通道. 披薩店能夠僅僅讓顧客知道訂單已經被下達,而不是經過打印到屏幕讓每個人都知道來確認訂單。
爲了能實現這個方法,披薩點須要知道如何聯繫客戶。因此客戶須要提供一個確認通道來回調。一般這樣的通道被稱爲ack.
pizzaAck.rho
爲何前面例子的確認信息並無顯示在屏幕上?
代碼中有錯誤
訂單沒有正確被接收
確認信息沒有發送到stdout
練習
以前的例子會致使元組空間中的@"Alice" 和 @"Bob"通道被污染.修改它,讓Alice 和 Bob 各自有本身的不可僞造的"name".
給發送的"names"權限
咱們剛剛看到顧客如何給出一個ack通道來獲取訂單肯定信息. 其實咱們能夠作得更好. 在咱們以前的代碼,任何一我的均可以在ack通道中聯繫客戶. 那意味着任何一我的均可以發送一個僞造的ack通道給客戶讓客戶認爲訂單已經下發成功,可是實際上並無。因此Alice 和 Bob 真的須要嚴格保管他們的不可僞造的"names". 由於給別人那個"name"就意味着別人能夠聯繫你。
privateAck.rho
解決方案是建立一個新的不可僞造的"name",而後發送它到披薩店以致於只有他們能夠回覆你。即便披薩店是在new alice的外面, 它仍然能夠在那個通道上發送信息由於Alice給了通道名字。這是一個很好的方法來委派權限。
在這個例子中,咱們相信披薩店只會在ack通道中 發送 ,可是要注意它也又多是在通道中接收信息,若是它想要的話。咱們將在下一節bundles中學習如何只給出一部分的權限出來。
Bob也想要訂一份披薩,給出一個不可僞造的ack通道。咱們應該在哪裏建立他本身的不可僞造的通道?
在他本身的那行,alice代碼後面
在Alice同一行
在程序代碼的第一行
stdoutAck 和 stderrAck
如今既然你知道了ack通道, 那麼你應該要知道其它兩種打印到屏幕的方法.它們是叫作stdoutAck 和 stderrAck的通道. 他們就像第一課說的stdout同樣工做,可是他們須要一個ack通道。
stdoutAck.rho
順便說一句,你注意到每次啓動一個新的元組空間都有一堆東西麼?這些東西其中4個東西是內置的用於接受屏幕打印的通道。另一些是用於加密的。咱們將在之後討論到。
練習
stdout!("1")|stdout!("2")|stdout!("3")
注意這段程序不會按照必定的順序打印出數字。他們是同時發生的。想象咱們如今真的要按照順序打印幾行。修改代碼,使用ack通道來保證數字按順序打印出來。
練習
預測這個程序怎麼運行(它會輸出什麼,它在元組空間怎麼簡化計算。)而後運行它來檢測你的預測。
new myChan in { myChan!("Hi There") } | for (msg <- myChan) {stdout!(*msg)}
若是你對上面的程序預測失敗,修改程序,讓程序按照你的想法運行。
提問
在 for(x <- y){Nil}中哪一個name是綁定的
x
y
Nil
在 new x in {Nil}哪一個"name"是綁定的
x
y
Nil
若是 pizzzaShop 是一個"name", 那麼 @pizzaShop是什麼?
一個name
一個process
無效的語法
爲何pizzaShopAck 代碼發送 "bob" 做爲一個ack通道而不是@"bob"?
沒有緣由; 就是一種風格。
由於 @"bob" 是一個name, 可是咱們必須發送processed。
那是給ack通道用的特別語法。