資訊內(nèi)容
一把雙刃劍:Scratch數(shù)據(jù)類型的隱式轉(zhuǎn)換

01
在前篇《從數(shù)據(jù)類型到計算思維》中,通過幾個簡單的測試,總結(jié)了幾條
源碼佐證:
_setCostume (target, requestedCostume, optZeroIndex) {if (typeof requestedCostume === 'number') {// Numbers should be treated as costume indices, alwaystarget.setCostume(optZeroIndex ? requestedCostume : requestedCostume - 1);} else {// Strings should be treated as costume names, where possibleconst costumeIndex = target.getCostumeIndexByName(requestedCostume.toString());數(shù)字類型的參數(shù)被當(dāng)做造型編號來執(zhí)行,字符類型的參數(shù)被當(dāng)做造型名稱來執(zhí)行(前提是有對應(yīng)的造型名稱時)
if (costumeIndex !== -1) {target.setCostume(costumeIndex);} else if (requestedCostume === 'next costume') {target.setCostume(target.currentCostume + 1);} else if (requestedCostume === 'previous costume') {target.setCostume(target.currentCostume - 1);// Try to cast the string to a number (and treat it as a costume index)// Pure whitespace should not be treated as a number// Note: isNaN will cast the string to a number before checking if it's NaN} else if (!(isNaN(requestedCostume) || Cast.isWhiteSpace(requestedCostume))) {target.setCostume(optZeroIndex ? Number(requestedCostume) : Number(requestedCostume) - 1);}字符類型的參數(shù)會被優(yōu)先“嘗試”轉(zhuǎn)換為數(shù)字類型,并作為造型編號執(zhí)行。
只是諸多會對數(shù)據(jù)類型進(jìn)行自動轉(zhuǎn)換的積木之一,也是在使用時最容易出BUG、最具代表性的積木。幾乎所有積木都會對數(shù)據(jù)類型進(jìn)行自動轉(zhuǎn)換,有的甚至對輸入的數(shù)據(jù)類型做了限制,如,無法直接在
積木中輸入字符。


02
轉(zhuǎn)數(shù)字類型失敗
然而并不是所有積木都“幸運(yùn)”地?fù)碛嘘P(guān)鍵詞的。那些沒有關(guān)鍵詞的、或者是參數(shù)不等于關(guān)鍵詞的,Scratch會如何處理呢? static toNumber (value) {// If value is already a number we don't need to coerce it with// Number().if (typeof value === 'number') {// Scratch treats NaN as 0, when needed as a number.// E.g., 0 + NaN -> 0.if (Number.isNaN(value)) {return 0;}return value;無法被轉(zhuǎn)換為數(shù)字類型的參數(shù)(即NaN),將會被轉(zhuǎn)換為0。有無數(shù)多的BUG都是因?yàn)檫@個原因而產(chǎn)生的,比如角色沒有移動到預(yù)期位置,卻總是在舞臺中央停滯不前。

03
布爾值的規(guī)則
其實(shí)這個小節(jié)的主題才是筆者動筆寫這篇文章的主要動機(jī)。它來源于一位群友的問題。一個非常經(jīng)典的問題。
比較運(yùn)算符的連續(xù)嵌套使用
初學(xué)者會這樣寫腳本的原因是將數(shù)學(xué)中的習(xí)慣帶到編程里來了(別問筆者是怎么知道的,問就是筆者也犯過相同的錯誤。。)乍一看好像沒有什么問題。但是要知道,程序是一步一步執(zhí)行的,像這樣嵌套關(guān)系的積木,也是先執(zhí)行上層的,再執(zhí)行下層的(相當(dāng)于數(shù)學(xué)中的括號)。3>2的結(jié)果是true(不打引號以區(qū)分字符類型),再比較true和1的大小。到這一步,不論接下去的結(jié)果如何,都應(yīng)該能發(fā)現(xiàn),和數(shù)學(xué)中連續(xù)比較的的3>2>1不一樣,這么寫是錯的,是肯定無法得到預(yù)期結(jié)果的。本著 Scratch 格物堂的“格物”精神,繼續(xù)往下看。true和1怎么比大小?這還不簡單嗎?《Scratch 3.0的大小比較是如何進(jìn)行的》一文中已經(jīng)說得很清楚了,字符類型的數(shù)據(jù)在參與比較運(yùn)算時,比較的是ASCII碼或者說是Unicode碼。而數(shù)字0的十進(jìn)制編號是48,A是65,a是97。就算Scratch不區(qū)分大小寫,二十六個字母怎么的也是排在數(shù)字后面,字母是肯定大于數(shù)字的,“true”>1肯定是true。
“true”>1
看似沒毛病
但是一運(yùn)行整個腳本。。。
于是開始倒推哪個環(huán)節(jié)出了問題。
用《Debug in Scratch —— Part 1》中提到的“氣泡輸出法”進(jìn)行排查:
曾經(jīng)引以為傲的“氣泡輸出法”
說“true”
還是沒問題
細(xì)心的讀者可能會發(fā)現(xiàn),上文中的true,是什么時候被打上引號的?true在參與比較運(yùn)算時,真的是“true”嗎?我們想當(dāng)然地以為true被轉(zhuǎn)換成了字符類型。但是不是字符類型還能是什么?NaN,難道被轉(zhuǎn)成了0嗎?0>1的確是false沒錯,好像說通了。但是換幾個用例再次進(jìn)行測試,發(fā)現(xiàn)結(jié)果又不太一樣。篇幅有限,不再進(jìn)行引導(dǎo)。直接上測試印證猜測
測試1:
布爾類型(true)參數(shù)參與算術(shù)運(yùn)算(+空字符)
測試2:
布爾類型(false)參數(shù)參與算術(shù)運(yùn)算(+空字符)
這兩個小測試足以證明,
true被轉(zhuǎn)換為數(shù)字類型時,會被轉(zhuǎn)換為1;false在被轉(zhuǎn)換為數(shù)字類型時,會被轉(zhuǎn)換為0.
在上文中的比較運(yùn)算符的連續(xù)嵌套使用示例中,第二次其實(shí)是在比較1>1,結(jié)果自然是false了。至于為什么“氣泡輸出法”會失效,這是因?yàn)?img src="upload/article/images/2020-11-17/9d01d293ccb1dc07b54315f8e0d12b6e.jpg" alt="upload/article/images/2020-11-17/9d01d293ccb1dc07b54315f8e0d12b6e.jpg" />這類積木會將參數(shù)轉(zhuǎn)換為字符類型。
04
實(shí)例
也許使用布爾值參與比較運(yùn)算的確實(shí)用價值不高,一般在案例實(shí)戰(zhàn)中不會這么用,僅僅需要了解其原因即可。但是筆者的的確確見過一種使用布爾值參與算術(shù)運(yùn)算,巧妙利用數(shù)據(jù)類型隱式轉(zhuǎn)換這個特點(diǎn)的案例。下面和讀者朋友們分享一下。一起盜竊案,有4名嫌疑人。這4人只有一名小偷。已知,這4名嫌疑人中,有且僅有1人在說謊。
首先用腳本把4個嫌疑人的供詞用邏輯表達(dá)式表示出來:
1號:“不是我?!?
2號:“小偷是3號?!?
3號:“小偷是4號。”
4號:“3號在說謊”
接著根據(jù)條件“4個嫌疑人中有且僅有1人在說謊”,可以推導(dǎo)出結(jié)論:以上4個邏輯表達(dá)式中,有3個是成立的,有1個是不成立的。再結(jié)合上文中g(shù)et的新技能:布爾值在被轉(zhuǎn)換為數(shù)字類型時,true會被轉(zhuǎn)換為1,false會被轉(zhuǎn)換為0,不難得出以下結(jié)論:
4名嫌疑人中,有且僅有1人在說謊
最后要做的就只有一件事了:遍歷,從小偷=1開始,逐個驗(yàn)證即可。篇幅有限,具體步驟就沒必要再細(xì)說了。
案例來源:《Scratch趣味編程進(jìn)階》?作者:謝聲濤
05
總結(jié)
如果用哲學(xué)中的矛盾觀來分析數(shù)據(jù)類型的隱式轉(zhuǎn)換這個問題的話,積木本身的種類、本身的參數(shù)類型是主要矛盾,居于主導(dǎo)地位,它決定數(shù)據(jù)將會被轉(zhuǎn)換成什么類型;而參數(shù)的數(shù)據(jù)類型則是次要矛盾,位居從屬地位。如果積木本身的參數(shù)類型與實(shí)際參數(shù)類型不匹配,則會優(yōu)先嘗試將其轉(zhuǎn)化為本身的參數(shù)類型,同時兼顧地“考慮”一下參數(shù)本身的“想法”,看看它是否“愿意”被轉(zhuǎn)換為那種類型,若“不愿意”,則另做打算(比如轉(zhuǎn)成0或者再比如
Scratch數(shù)據(jù)類型的隱式轉(zhuǎn)換這個問題,筆者秉持辯證的觀點(diǎn)來看待。首先這樣無疑對新手來說無疑是十分友好的,易上手。否則動不動地給你報個錯,如果對Scratch的數(shù)據(jù)類型不夠了解的話,幾乎解決不了。那么現(xiàn)有的教學(xué)知識體系中又要多一塊龐大卻又對邏輯思維能力的提升不大且極為枯燥的內(nèi)容了,這絕對是在“勸退”初學(xué)者。另一個優(yōu)點(diǎn)就是,只要你的想象力足夠豐富,就能利用這個特點(diǎn)做出精妙的案例(前提是你要清楚地知道自己在做什么)。
但是隱式轉(zhuǎn)換帶來的負(fù)面影響也同樣地明顯。相比強(qiáng)類型的語言,Scratch在數(shù)據(jù)類型這方面來說顯得不夠嚴(yán)謹(jǐn)。其次,和其他弱類型語言一樣,隱式轉(zhuǎn)換總是被打上“它們的存在將導(dǎo)致錯誤的發(fā)生”的標(biāo)簽。一如上文中的3>2>1。Scratch數(shù)據(jù)類型隱式轉(zhuǎn)換所造成的BUG數(shù)不勝數(shù),細(xì)分下去種類繁多。并且就像他的名字一樣,十分隱蔽,極難排查,即使像上文中那樣運(yùn)用一般的debug方法,也很有可能會因?yàn)樵俅伟l(fā)生隱式轉(zhuǎn)換而失效。
聲明:本文章由網(wǎng)友投稿作為教育分享用途,如有侵權(quán)原作者可通過郵件及時和我們聯(lián)系刪除

- 上一篇
Scratch教程(九)——打磚塊游戲
前言 有一段時間沒有更新Scratch教程,一來是孩子開始學(xué)習(xí)Python編程,在解決實(shí)際問題的時候畢竟Scratch這種玩具式的語言還是很難勝任的;二來是由于學(xué)校一直推行的是logo語言編程。不過這種狀況已經(jīng)改變,從今年開始,學(xué)校終于打算開設(shè)Scratch課程,對于初學(xué)計
- 下一篇
語音模塊的使用——scratch編程
語音模塊具有存儲語音數(shù)據(jù)并能利用單片機(jī)編程控制播放的功能。本節(jié)課內(nèi)容為將語音模塊與單片機(jī)系統(tǒng)主板相連,并編制程序控制循環(huán)播放序號為68的語音片段“世界那么大,我想去看看”。 一、硬件搭建 本節(jié)課程內(nèi)容是迎賓機(jī)器