成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

通俗的方式理解動態(tài)類型,靜態(tài)類型;強類型,弱類型

周國輝 / 1408人閱讀

摘要:不允許隱式轉(zhuǎn)換的是強類型,允許隱式轉(zhuǎn)換的是弱類型。拿一段代碼舉例在使用調(diào)用函數(shù)的時候會先生成一個類模板運行時生成,執(zhí)行的時候會生成類模板,執(zhí)行的時候會生成類模板。

0 x 01 引言

今天和一個朋友討論 C++ 是強類型還是弱類型的時候,他告訴我 C++ 是強類型的,他和我說因為 C++ 在寫的時候需要 int,float 等等關(guān)鍵字去定義變量,因此 C++ 是強類型的,我告訴他 C++ 是弱類型的他竟然還嘲笑我不懂基礎(chǔ)。

我又嘗試去問了另外一個同學 Python 是強類型還是弱類型的時候,得到的竟然是弱類型,就因為定義變量沒有 int,float!

然后我想找一些網(wǎng)上的資料試圖告訴他們他們是錯的(我是對的),結(jié)果發(fā)現(xiàn)網(wǎng)上的資料大多為了嚴謹結(jié)果把簡單的問題(其實并不簡單)說的很復雜。比如:知乎上的一些 回答。所以用通俗的方式,以大多數(shù)程序猿(媛)所需要了解的知識去介紹類型系統(tǒng),但是又不喪失嚴謹性就是這篇文章寫的意義。

0 x 02 什么是動態(tài)(靜態(tài))類型,強(弱)類型

基礎(chǔ)版本

編譯時就知道變量類型的是靜態(tài)類型;運行時才知道一個變量類型的叫做動態(tài)類型。比如:

編譯器在將 int age = 18; 這段代碼編譯的時候就會把 age 的類型確定,換言之,你不能對他進行除以 0 的操作等等,因為類型本身就定義了可操作的集合;但是像 C++ 里常見的 auto ite = vec.iterator(); 這種也屬于靜態(tài)類型,這種叫做類型推導,通過已知的類型在編譯時期推導出不知道的變量的類型。在靜態(tài)類型語言中對一個變量做該變量類型所不允許的操作會報出語法錯誤。

但是像 var name = student.getName(); 這行 JavaScript 代碼就是動態(tài)類型的,因為這行代碼只有在被執(zhí)行的時候才知道 name 是字符串類型的,甚至是 null 或 undefined 類型。你也沒辦法進行類型推導,因為 student.getName 函數(shù)簽名根本不包含返回值類型信息。后面會介紹通過一些其他手段來給函數(shù)簽名加上類型。在動態(tài)類型中對一個變量做該變量類型所不允許的操作會報出運行時錯誤。

不允許隱式轉(zhuǎn)換的是強類型,允許隱式轉(zhuǎn)換的是弱類型。比如:

在 Python 中進行 "666" / 2 你會得到一個類型錯誤,這是因為強類型語言中是不允許隱式轉(zhuǎn)換的,而在 JavaScript 中進行 "666" / 2 你會得到整數(shù) 333,這是因為在執(zhí)行運算的時候字符串 "666" 先被轉(zhuǎn)換成整數(shù) 666,然后再進行除法運算。

高級版本

需要先介紹一些基本概念:

Program Errors(程序錯誤)

trapped errors:導致程序終止執(zhí)行(程序意識到出錯,使用對應(yīng)的錯誤處理機制),如除 0,Java 中數(shù)組越界訪問

untrapped errors:程序出錯后繼續(xù)執(zhí)行(其實并不一定保證繼續(xù)執(zhí)行,程序本身并不知道出錯,也沒有對應(yīng)的錯誤處理機制),如 C 語言里的緩沖區(qū)溢出,Jmp 到錯誤地址

Forbidden Behaviors(禁止行為)

程序在設(shè)計的時候會定義一組 forbidden behaviors,包括了所有的 untrapped errors,可能包括 trapped errors。

Well behaved、ill behaved

well behaved: 如果程序的執(zhí)行不可能出現(xiàn) forbidden behaviors,則稱為 well behaved

ill behaved: 只要有可能出現(xiàn) forbidden behaviors,則稱為 ill behaved

他們之間的關(guān)系可以用下圖來表達:

從圖中可以看出,綠色的 program 表示所有程序(所有程序,你能想到和不能想到的),error 表示出錯的程序,error 不僅僅包括 trapped error 和 untrapped error。

根據(jù)圖我們可以嚴格的定義動態(tài)類型,靜態(tài)類型;強類型,弱類型

強類型:如果一門語言寫出來的程序在紅色矩形外部,則這門語言是強類型的,也就是上面說的 well behaved

弱類型:如果一門語言寫出來的程序可能在紅色矩形內(nèi)部,則這門語言是弱類型的,也就是上面說的 ill behaved

靜態(tài)類型:一門語言在編譯時排除可能出現(xiàn)在紅色矩形內(nèi)的情況(通過語法報錯),則這門語言是靜態(tài)類型

動態(tài)類型:一門語言在運行時排除可能出現(xiàn)在紅色矩形內(nèi)的情況(通過運行時報錯,但如果是弱類型可能會觸發(fā) untrapped error,比如隱式轉(zhuǎn)換,使得程序看起來似乎是正常運行的),則這門語言是動態(tài)類型

舉個栗子:

在 Python 中執(zhí)行 test = "666" / 3 你會在運行時得到一個 TypeError 錯誤,相當于運行時排除了 untrapped error,因此 Python 是動態(tài)類型,強類型語言。

在 JavaScript 中執(zhí)行 var test = "666" / 3" 你會發(fā)現(xiàn) test 的值變成了 222,因為這里發(fā)生了隱式轉(zhuǎn)換,因此 JavaScript 是動態(tài)類型,弱類型的。更為夸張的是 [] == ![] 這樣的代碼在 JavaScript 中返回的是 true,這里是具體的 原因。

在 Java 中執(zhí)行 int[] arr = new int[10]; arr[0] = "666" / 3; 你會在編譯時期得到一個語法錯誤,這說明 Java 是靜態(tài)類型的,執(zhí)行 int[] arr = new int[10]; arr[11] = 3; 你會在運行時得到數(shù)組越界的錯誤(trapped error),這說明 Java 通過自身的類型系統(tǒng)排除了 untrapped error,因此 Java 是強類型的。

而 C 與 Java 類似,也是靜態(tài)類型的,但是對于 int test[] = { 1, 2, 3 }; test[4] = 5; 這樣的代碼 C 語言是沒辦法發(fā)現(xiàn)你的問題的,因此這是 untrapped error,因此我們說 C 是弱類型的。

下圖是常見的語言類型的劃分:

另外,由于強類型語言一般需要在運行時運行一套類型檢查系統(tǒng),因此強類型語言的速度一般比弱類型要慢,動態(tài)類型也比靜態(tài)類型慢,因此在上述所說的四種語言中執(zhí)行的速度應(yīng)該是 C > Java > JavaScript > Python。但是強類型,靜態(tài)類型的語言寫起來往往是最安全的。

0 x 03 動態(tài)類型與靜態(tài)類型的區(qū)別,如何利用好動態(tài)類型

靜態(tài)類型由于在編譯期會進行優(yōu)化,所以一般來說性能是比較高的。而動態(tài)語言在進行類型操作的時候(比如字符串拼接,整數(shù)運算)還需要解釋器去猜測其類型,因此性能很低;但是現(xiàn)代的解釋器一般會有一些優(yōu)化措施來提升速度,拿 JavaScript 的 V8 解釋器舉個栗子:

V8 的優(yōu)化過程(粗略版本)

我們知道,像 Java / C++ 這樣的靜態(tài)類型語言對于對象一般都會有個類模板(一般調(diào)用函數(shù)的時候都是去類模板找的)。而像 V8 這種則是會在運行時創(chuàng)建類模板,從而在訪問屬性或調(diào)用方法的時候僅需要計算該屬性在類模板中的偏移就可以了;傳統(tǒng)的 JavaScript 對象一般是通過 Hash 或 Trie 樹實現(xiàn)的,但是查找的效率很低。拿一段代碼舉例:

function Point(x, y) { 
this.x = x; 
this.y = y; 
} 
var p1 = new Point(1, 2);

在使用 new 調(diào)用 Point 函數(shù)的時候會先生成一個 class0 類模板(運行時生成),執(zhí)行 this.x = x 的時候會生成 class1 類模板,執(zhí)行 this.y = y 的時候會生成 class2 類模板。具體的轉(zhuǎn)換過程如下圖:

為一個對象確定一個類模板可以極大的提升屬性的訪問速度,類模板的確定就是通過走圖里的路徑(轉(zhuǎn)換路徑)。每當你增加或刪除對象的屬性的時候都會導致對象的類模板發(fā)生改變,甚至你增加的順序不同也會生成不同的類模板!

V8 如果發(fā)現(xiàn)一個方法被調(diào)用(傳入相同類型的參數(shù))多次時,會使用 JIT 將函數(shù)編譯成二進制代碼,從而提升速度。

結(jié)合 V8 總結(jié)的優(yōu)化方案:

不要輕易的增加刪除一個對象的屬性,對于已有的屬性盡量做到保證類型的不變,保證隱藏類盡可能被復用

實例化屬性的時候盡可能保證屬性添加的順序一致性,保證隱藏類和優(yōu)化代碼可以被復用

盡可能重復調(diào)用方法,傳的參數(shù)的個數(shù)和類型要在多次調(diào)用時要保持一致

對于數(shù)組,最好使用 push,unshift 等方法去改變數(shù)組大小,緊密的數(shù)組在 V8 中是以連續(xù)的地址存的,不要隨意去刪除數(shù)組中的元素,因為稀疏數(shù)組在 V8 中是一個 hash 表

V8 存儲整數(shù)用的是 4 個字節(jié),出現(xiàn)大整數(shù)時將會涉及到隱式類型轉(zhuǎn)換,性能降低,因此盡量不要讓整數(shù)超過 32 bit

0 x 04 如何避免弱類型語言所帶來的問題

弱類型語言由于在運行時缺乏類型系統(tǒng),因此很容易出現(xiàn)類型操作上的 untrapped error;C 語言中我們前面介紹了數(shù)組訪問越界的情況,這里我們以弱類型語言 JavaScript 為例:

盡量使用嚴格比較符號,如:===

盡量不要讓字符串與其他類型的變量進行運算操作

復雜對象不要在運算符上進行操作

0 x 05 語言類型靜態(tài)化的方案

像 JavaScript 這種動態(tài)類型的語言靜態(tài)化后對運行時的安全性,效率肯定會有很大的提升的,目前有 TypeScript 這種預編譯的方案;還有就是像 flow 這樣的通過注釋來標識類型的方案。

0 x 06 總結(jié)

寫到最后,我才發(fā)現(xiàn)文章的標題沒取好,就這樣吧。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/92387.html

相關(guān)文章

  • 做一個好前端必須要知道事——JS語言

    摘要:準確的理解,是編譯型語言,源代碼整個編譯成字節(jié)碼,字節(jié)碼,是解釋型語言。是一個非常靈活的語言,支持命令式和函數(shù)式編程。編譯型語言通常會用做配置文件,因為我們通常不會改編譯后的字節(jié)碼。 編程語言按各種方法可以分為各種類型,現(xiàn)在讓我們來看看JS屬于什么類型語言 解釋型語言 按編譯執(zhí)行過程,可以分為編譯型語言和解釋型語言。比如 c 語言,必須先經(jīng)過編譯生成目標文件,然后鏈接各個目標文件和庫...

    Near_Li 評論0 收藏0
  • 類型、類型、靜態(tài)語言、動態(tài)語言區(qū)別?

    摘要:弱類型強類型會報錯靜態(tài)類型以上是的代碼,靜態(tài)類型語言在編譯時遇到錯誤就會立即提醒。備注意思是陷阱,也被稱為異?;蚬收稀? 弱類型: 1+2 12 強類型: 1+2 會報錯 靜態(tài)類型: public void ShowHi() { int a = Hi! string b = a; } 以上是c#的代碼,靜態(tài)類型語言在編譯時遇到trap錯誤就會立即提醒。 動態(tài)類型:...

    edagarli 評論0 收藏0
  • 基礎(chǔ)沖刺

    摘要:事實上,確實存在多種解釋器。在命令行下運行就是啟動解釋器。最常用的,自帶的就是這個是基于之上的一個交互式解釋器,也就是說,只是在交互方式上有所增強,但是執(zhí)行代碼的功能和是完全一樣的。但是的解釋器很多,但使用最廣泛的還是。 以下資料大多參考的此篇博客:http://www.cnblogs.com/alex37... 基礎(chǔ)沖刺 編譯型語言:C、C++ 運行之前都需要一次編譯,編譯成可以...

    sunny5541 評論0 收藏0

發(fā)表評論

0條評論

周國輝

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<