首頁>Club>
現實中想幹點事實,學習下程式設計,看見開發工程師待遇都是挺好的,想進攻學習開發,需要做啥準備?
14
回覆列表
  • 1 # 瑞豆PTE

    正好最近公司一個同事想學程式設計。就把這個貢獻給題主了~~~

    每一門學科都有它自己的思維方式,學習的過程就是透過它的知識描述、例項、習題來去感知這門學科究竟是用什麼樣的思維去運作的。在初學的時候,去感知這門學科的思維方式是非常重要的,非常重要的,非常重要的。

    舉個例子,比如音樂,別人給你唱一段,只要你不是五音不全,或者音太高或太低,那麼你當場就模仿一遍也不是什麼難事。但是,真正懂音樂的人,會知道他唱的每一個音的音高是什麼,是什麼風格的、甚至腦中都已經響起了和絃。

    又比如在繪畫領域,很多學過素描的都能直接照著描這棵樹:

    《與西斯圖合作的樹的習作》 -- 達芬奇

    但是,如果你去搜一下達芬奇的《論繪畫》,你就會明白,這是一顆不存在這個世界的樹,但是卻是一顆真實的樹。

    迴歸正題

    其實學程式設計也一樣,逐行抄程式碼的作用,當然會有,但是並不大。你應該明確自己逐行抄程式碼的意義;那就是熟悉這門語言的語法的拼寫,而已,也就是強行記語法&單詞,你需要儘早擺脫抄程式碼,學習一週以內,你就不應該一句一句地抄了。你真正想學的程式設計,是一種思維活動,這個涉及到你是否真的明白教材裡面的知識。

    從我之前教人程式設計總結的一些經驗給你說說如何入門程式設計。

    PS:比較長。

    0、初學程式設計的核心問題

    據我的經驗,初學程式設計所遇到的問題無非就是以下3種:

    思路混亂(問題領域)不清楚每行程式碼的作用(靜態思考)不知道每行程式碼當前所處的狀態(動態思考)

    思路混亂,這個問題在很多的程式設計師中也會出現,它屬於領域問題,在於對需求理解不夠,對問題的分析不到位所導致的。而對於初學者,則會容易出現另一個問題:把問題領域等同於程式設計問題。也就是從一開始就以 “我要寫程式碼” 的方式去思考,結果越想越混亂。為什麼呢?因為初學程式設計首先對語法就不熟悉,更別提語言裡面的各種概念了。所以,以 “寫程式碼” 的方式直接思考問題領域中的問題,本身就會讓你的思維更加混亂。

    例如,我現在叫你寫一個判斷9102年是不是閏年的程式,如果你的腦子裡面飛出來一堆 “應該怎麼寫?”、“是用if嗎?”、“還是要用到for?”、“if語句怎麼寫來著?”、“糟糕,我忘了main函式的寫法了”;那麼你應該先去買杯奶茶冷靜一下(順便給我帶一杯)。

    接下來,你應該準備紙筆,邊喝奶茶邊想 “閏年是什麼意思?”、“我應該先判斷它能不能被4整除(在紙上寫下 判斷9102/4是整數)”、”噢,這樣還不行,我還應該判斷它是否同時滿足不能被100整除(在紙上寫下 判斷9102/100不是整數)“、“哎呀,還有還有,如果剛好是400的倍數,那麼雖然可以被100整除,但是也是閏年(在紙上寫下 判斷9102/400是整數)”。你看,這就是所謂的問題領域,跟程式設計其實一毛錢關係都沒有,大家都是這樣思考問題的,而程式設計,只是把問題轉化為語句罷了(其實你在紙上寫下這些的時候,也是把問題轉化為中文而已,只是因為你對中文的表達形式太熟悉了,所以能直接寫出來)。

    不清楚每行程式碼的作用,你已經知道什麼是閏年了,也知道靠你自己的腦子裡的數學運算知識,就可以知道9102年是不是閏年了。但是,程式應該如何表達你的思維過程呢?這個就是你需要學習的所謂的“程式語言”,也就是它的語法以及語句所表達的含義。

    不知道每行程式碼當前所處的狀態,這點對於初學者來說是個非常頭疼的問題,因為它需要你去感知程式碼在CPU上跑的時候,究竟是怎麼樣的,也就是你的大腦在模擬CPU,這也是程式設計師的標準日常。而對於初學者來說,最難越過的就是這道坎。

    這相當於什麼呢?比如在學音樂的時候,會不斷地聽音、模唱、腦補這個音在五線譜上的位置,以及在你所學樂器中如何表現出來,直到你能夠看到五線譜上的音符的時候,腦中就自然地響起那個音,這在音樂中被稱為內心聽覺(敲黑板)。

    或者說你對繪畫比較熟悉?那麼在學習繪畫的時候,學習勾線,然後看看別人的畫是怎麼佈局的、怎麼勾線的,鍛鍊自己在畫的時候就能在腦中清晰地腦補出想要畫的事物。

    你看,其實每個學科都是同樣的,需要你培養對這個學科的感知能力。程式設計也不例外,它要求你在看別人的程式碼或者自己寫程式碼的時候,你的腦中應該有清晰的“影象”,並且這個影象是動態的,隨著你關注問題的不同部分,這個影象就會不同。

    OK。既然知道了初學會面臨什麼樣的問題,那麼就等於有了目標。不過,在談如何解決這些困難之前,我們先來學點最簡單的“哲學”,當然,不是專業課上的哲學,而是經過簡化的程式設計哲學。

    PS:另外提幾句,如果題主是想以程式設計為主業或者對程式設計特別感興趣,那麼建議你從C、Java/Kotlin、Golang等(半)編譯型語言,理由很簡單,這些語言會迫使你去認知你寫的程式碼到CPU執行會經過什麼步驟,讓你對計算機基礎概念的理解有極大的幫助。我的建議當然是直接學C,雖然入門之後的指標、垃圾回收等概念有些困難,但是你會了解到非常多計算機原理的知識,對你未來學習其他語言,以及精進的幫助是非常大的。如果你只是想學個程式設計來輔助你的工作,比如,你是搞金融的、搞地質勘測的、社交/交易資料分析的,那麼學個Python、JavaScript就非常合適,沒必要去碰真·程式設計師的那些“燒腦”的東西。(最近不知道哪來的風氣,說C、Java不適合入門,要學Python之類的指令碼語言,並且一律全是學爬蟲,看得我一臉懵逼。我只能說,如果你先學了這些語言,倒也問題不大,只是你可能很難再去認真學計算機原理了;為什麼?因為你會選這些所謂的“簡單”的語言的時候,就已經表明你並沒有想要去接觸計算機原理了,而當你學會之後,你就會有一種“我都已經學會程式設計了”,我還學那些幹嘛?當然,一切還是看你自己。)

    1、抽象&認知

    題主千萬不要被抽象和認知這兩個詞嚇到。大家都說程式設計師需要抽象思維,並且抽象思維聽起來好像很難的樣子。其實抽象比你想象的要簡單的多,也普遍得多。比如,當你在街上看到一隻狗,你的腦中就會浮現“狗”這個詞,以及“狗很可愛”、“狗有很多毛”、“狗有尾巴”等特徵,還有“狗會跑”、“狗會尿尿”、“狗會吠”、“狗會咬人”等行為。其實這個時候,你就是在利用抽象能力,只是多數情況下你會忽略這種思緒,因為它實在是太平常了。

    而你現在,需要做的,就是如何刻意去練習抽象,從最基礎的認知開始:抽象就是從具體事物中提取出它們的共同特徵。你看,剛剛說的對狗的認知,就包含了大部分的狗都符合的特徵和行為。

    所以,當我們要去學習“大象”的本質是什麼之前,首先要看到整頭大象大概是長什麼樣的。

    認知,就是我要講的第一個重要的點。很多初學者在學習的時候,並不是真正的對程式設計有了認知,而是隻是記住了程式語言的語法,而不是它的核心概念。什麼叫做核心概念呢?下面就開始詳細的說明:

    在大多數邏輯型語言中(例如比較主流的C/C++、Java、Python;而所謂非邏輯語言,是指像Json、HTML、CSS等不包含邏輯的描述語言),都會存在一些核心的基本概念,這些概念其實和語法沒有任何關係,語法僅僅是為了表達這些概念而存在的。對於初學者來說,並不要求立刻就理解這些抽象的概念。但是,這是我們的學習目標,我們的學習目標並不是學會X語言的語法,而是語法背後的核心概念(敲敲~敲黑板)。

    程式設計其實就是處理各種各樣的資料。說得很抽象對吧?別怕,跟著我來。

    大多數程式語言一上來都會給個“Hello World!”程式,這就是我上面所說的那頭“大象”,它的意義就是讓你先對這個語言長成什麼樣有個感性的認識。它告訴你,在我這個語言裡面,你這樣寫,就能在終端/螢幕上輸出“Hello World!”,讓你先體驗一下即時反饋的樂趣。這時,你可以做的最簡單的事情就是去修改輸出的內容,比如改成“Hello, XNan!”,你就能感受到你的修改是有效的。不過,接下來,就沒那麼簡單的,因為當你看到這頭“大象”之後,就要開始“解剖”這頭“大象”了(動物保護協會的不要來找我啊~~~)。

    比如說C語言,你會接觸到的是變數和資料型別,然後是各種運算子,接著是if語句,再接著是while語句,再再接著就是for語句,說不定還有switch語句,一直到結構體、聯合體、指標、函式 balabalabala~。眼花繚亂,一臉懵逼,生無可戀······

    但是,你先拿起筆,在本子裡記下下面的列表:

    資料儲存(定義變數&資料型別&自定義型別)資料運算(運算子)條件判斷(if語句&switch語句)重複(while、do...while、for迴圈)拆解問題(函式)

    是的,這就是我說的核心概念,幾乎任何一種邏輯型語言,都會存在上面這個列表中的概念,唯一不同的,就是這個語言究竟是如何去表達它的。

    再舉個 :“我”,其實是一個概念,還記得你小時候,你媽媽或者幼兒園老師教你 “我” 這個概念的時候的情景嗎?一般都會指著自己,然後說 “我”,來去傳達這個概念給你,而這個“我”字,只不過是表達 “我自己” 這個概念的形式而已,在英語中,也有 “我” 的概念,並且表現形式很不一樣,使用“I”來表達“我”這個意思的。

    那麼現在你應該大概能理解了,定義變數這種具體的行為,其實只是資料儲存的概念,它的本質是你有了一個可以儲存資料的空間,你可以把一些資料放進去。那麼程式設計思維就構建起來了。其他幾個也是同理,你在學習的時候,你要去理解語法背後的概念。那麼現在也就有了學習的方法。

    好了,有了目標,也有了學習方法,就可以開始學習了。

    2、分析問題

    上面已經說到,初學者第一個面臨的問題是思路混亂,也就是沒有對問題領域有清晰的認識,沒有在邏輯層面解決所提出的問題,而上面所使用的閏年的例子已經說得很清楚了。在你還沒有非常熟悉語言的語法的時候,你需要現在紙上把問題先解決了。為什麼呢?因為你對所使用的工具還不熟悉,所以你根本沒辦法一邊思考問題,一邊思考程式碼怎麼寫,所以你需要先分開思考。想要越過這個坎,還是很簡單的,看到習題的時候,首先在腦子裡去解決問題,然後再把問題分步驟寫在紙上,最後再去找每一步,在你所學習的語言裡面是如何表達的。很容易,對吧?不就是一杯奶茶的事情嘛,如果不夠,那就兩杯。

    3、理解每行程式碼的作用

    理解一行程式碼究竟是什麼作用的,是一種靜態思考,這是必須的,這就是上面所舉的音樂和繪畫的例子中的一個概念;在寫程式碼的時候,腦子裡面應該想些什麼。你需要非常清楚地知道你寫的這一行程式碼的作用究竟是什麼。

    比如

    這行程式碼,應該在腦子裡想什麼呢?下面給出不同層次的思緒。

    初等:我定義了一個整數型別的變數,名字叫num,這個變數等於42(這個思緒嚴格來說是錯的)進階:我定義了一個可以儲存int型別資料的變數,命名為num,並且我給它賦值為42(這個是正確的,但是認知太淺了)原理:我在棧中有一個int型大小的空間,這個空間儲存著42這個值的二進位制碼,這個空間···唔···就命名為num吧(如果寫這句程式碼時,潛意識是這樣想的,那麼你已經擁有真正的程式設計師思維了)底層:我在這個函式棧暫存器指標(例如ESP)所在的第N個位置儲存著42這個值,我可以透過num這個名字來取到這個值,唔···可能有些CPU會有不同的行為(初學者就不用考慮這一層了,如果對彙編沒什麼概念的話。而且正常來說也沒必要)物理:CPU暫存器的某些位置會聚集電荷,表示儲存了資料······(額······還是去搞積體電路吧)神話:And God said, "Let there be light" and there was light.(行了,已經不用學了)

    OK,扯淡完畢。對於初學者,應該可能目前處於“初等”的思維,有些可能可以達到“進階”思維。我的建議是,努力達到“原理”思維。至於“底層”思維,如果有興趣可以去學彙編,瞭解CPU的構造,如果沒興趣,也沒必要。

    只有一個例子,可能還無法理解。那麼就針對if語句來舉例子吧。

    這裡就不列每個思緒了,直接說你腦子應該想什麼:我想要判斷num變數是不是大於或等於42,num的值儲存在棧的某個空間裡面,這樣我就能取到它的值,並且使用>=運算子來進行判斷,if語句就是這樣的,使用單詞if,後面括號裡面的是條件,條件表示式會返回這個判斷是不是對的,如果是對的,那麼CPU就會跳到執行“對的”情況下的程式碼,也就是那句語句。很清晰,對吧?那就按照這個方式,去真正理解程式裡面每一句程式碼的作用是什麼。

    以上,看起來很繁瑣,但是,初學的時候,你必須這樣去思考,一開始可能會很慢,看程式碼可能一行要看幾秒甚至幾十秒才能反應出它的含義,但是隨著你這樣的思考越來越頻繁,不出半年,你就可以瞬間反應出來,並且都是潛意識的活動,你不注意都可能沒發現自己已經想的那麼深入了。

    4、跟蹤每行程式碼執行時所處的狀態

    這是初學者面對的最難解決的問題,因為初學者的思維比較單一,並且在對語法都還不熟悉的情況下,更加難保持清晰的認知狀態,在這些debuff疊加的狀態下,讓初學者苦不堪言。不過沒關係,下面我就來談談如何解決這個問題。

    首先,這裡的“執行時”,並不是說程式真的在執行的時候,而是我們在寫程式碼的時候,就要在腦中模擬執行這個程式。那麼什麼叫做狀態呢?也就是當程式執行到某行程式碼的時候,究竟有多少資料?這些資料的含義是什麼?這些資料的值我能確定嗎?這些值在現在這行程式碼執行的時候,值域範圍是什麼?我應該如何處理它才能達到我的目的?

    上面的所有問題,都是要你在寫程式碼的時候,能瞬間回答的問題。下面我就拿判斷閏年的例子,來說明如何動態思考:

    吶,透過這個簡單的例子。應該毫無壓力的就能理解所謂的 “跟蹤每行程式碼執行時所處的狀態”了。

    5、例項

    下面就用一個稍微複雜一點的例項來結束這個回答吧。

    我個人在教初學者的時候,習慣用判斷一個數是否是素數來作為最基礎的例項。原因是它簡單,不管是問題的描述還是用程式碼去實現,都很簡單,但是卻用到了語言的所有基礎概念和語法(變數定義、條件判斷、迴圈)。這裡我並不打算講函式,只作為對那3個問題的一個講解例項而已。

    首先,我們先在問題領域把這個問題解決了。

    素數的定義:一個數,如果只能被1和它本身整除,那麼它就是一個素數。

    那麼在邏輯上,我們是怎麼去判斷的呢?比如說,一個數,如果比較小,那麼你的大腦很容易就能判斷出來,比如5,是一個素數,它不能被234整除,而大於5的數就肯定不可能整除5了。再比如,17,它不能2~16的數整除,但是···你確定嗎?你有拿每個數去除過嗎?沒有,那麼你現在就去試試,拿2 3 4 ~ 16每個數都去除一下,然後告訴我,17是不是素數?

    PS:當然其實你只需要除到8就可以了,因為一個數被任何一個數整除的最小值是2,所以能整除17的整數絕對不會超過8,不過我們這裡不考慮

    是的,17確實是素數,但是如果你沒有一個一個去除過,你就不能保證它的確是素數,而計算機,判斷一個數是否是素數的思路,也是一樣。你需要從2開始,拿每一個數去除17,這樣才能證明17是素數。那麼,我們就在問題領域裡面,解決了這個問題了。但是,如果按照這個思路,你可能會寫出每個除數一行程式碼來判斷的程式,這樣一點都不符合程式設計師“偷懶”的思維,還不如我在紙上直接寫來得快呢,是吧?那麼應該如何寫呢?

    OK。看程式碼(我這裡使用C語言,如果你學的是其他語言,那麼你可以作為參考,然後自己用目標語言去寫):

    下面跟著我來一步一步地在大腦中執行程式碼。注意格式,適當的空行有助於分隔程式碼,也有助於你的思路清晰。

    首先,main函式是C語言的入口,對於初學者,你只要知道,把程式碼寫到main下面的大括號裡面就可以了。第5行,定義int型的變數num,這個變數的含義是我們要判斷是否為素數的數字。記住你定義了一個這樣的變數。第7行,定義int型的變數i,這個變量表示num需要除的數,它是動態的,你會在每次除完以後,將它+1,比如先讓num除以2,然後再除以3,再除以4······,所以你必須很清晰地知道i的作用。它是用來充當每次驗證num的除數。因為我們判斷素數是從2開始的,所以它的初始值是2。第8行(開始判斷是否進入迴圈),現在想想那幾個問題;究竟有多少資料?這些資料的含義是什麼?這些資料的值我能確定嗎?這些值在現在這行程式碼執行的時候,值域範圍是什麼?在執行到這行程式碼的時候,num和i的作用你必須要很清楚。那麼就可以這樣思考,當前的i為2,num的值是什麼,我們並不需要知道,但我們依然可以先假設為17。總之我們的目的就是看i是不是比num小,如果是,我們就應該拿i去除num。所以我們進入迴圈的條件就是 i < num。而按照目前的資料來看,2 顯然小於 17。所以會進入迴圈。第10行(第1次進入迴圈),上面說了,i當前的值是2,我們拿它去除num,並且看看餘數是不是0,如果餘數是0,就表示被整除了,那麼說明就不是素數;如果不能被整除,那麼就繼續檢查下一個數字。而在這行程式碼中,我們拿2 去除 17,並不能整除,所以就會跳過if的大括號裡面的程式碼。第15行,這就是將i的值+1,注意了,當執行到這行程式碼的時候,i的值,改變了,根據當前狀態,i的值會變成3,而num依然是17。接下來,就是很多初學者會腦抽的地方,那就是程式碼執行的順序會改變,它不會16行、17行、18行這樣執行。因為while語句是迴圈語句,並且while的整個大括號都屬於迴圈體,所以當執行到16行的時候,它會重新回到第8行,並且重新執行判斷。接下來就是這樣的,我們繼續按照當前變數的狀態來執行。第8行(第二次判斷是否進入迴圈),然後還是那幾個問題,你要清楚i和num的狀態。剛剛已經知道了,i的值被+1了,所以就等於3了。3 < 17 依然成立,所以繼續進入迴圈。第10行(第2次進入迴圈),這裡最後一次強調你要清楚i和num的狀態。i 等於 3,那麼17 / 3並不能整除,所以依然跳過if的大括號裡面的程式碼。第15行,再次將i的值+1,所以就變成4了。接下來,就會一直執行迴圈,不斷拿新的i值去除num,只要每次都不會除盡,那麼迴圈就會繼續,i不斷+1,一直到i的值等於num的值為止,在這裡,i最終會等於17。那麼我們這時就會再回到第8行,判斷是否進入迴圈的時候。來看看這個臨界時刻。第8行(經過15次的迴圈之後···),可以發現,17 < 17 顯然不成立了,所以這個時候,就不會再進入迴圈了,而是會直接跳過迴圈,繼續執行。第18行,執行到達這裡,就說明我們已經有明確的可以判斷num是否為素數的條件了。那麼條件是什麼?我們來看看,如果一個數不是素數,那麼在i 小於 num並且被除的時候就會被除盡,例如,如果我們的num是9,那麼在i等於3的時候,第10行就會判斷num能夠被i整除,所以就會進入if語句的大括號裡面,也就是第12行的語句,這條語句表示直接跳出迴圈,所以當i被整除的時候,就會直接跳出迴圈,也就會直接跳到現在這行程式碼。現在就簡單了,如果i的值能夠被整除,那麼它當然就還沒被加到num的時候,就已經跳出來了,所以i一定不會等於num。但是如果i一直沒有被整除,那麼最後必然會等於num(這也是我為什麼說先不管可以除到num的一半就可以),所以當i等於num的時候,就說明num是素數;不相等的時候,就表示num不是素數。

    這個程式,就已經分析完了。那麼簡單的程式囉嗦了那麼多,目的是讓初學者去感知寫程式碼的時候,大腦就行是如何運作的。

    6、總結

    在程式設計裡面,最難的是思維的轉變,很多說學不會程式設計的,其實是因為並沒有把思維轉到程式中來。初學的時候,千萬不要以為抄個程式碼,執行成功,結果也對就萬事大吉了。而是要認真看書、看文件,去搞清楚每一個概念,只有理解了概念,才是真的會程式設計。也不要覺得按照上面的例項分析來去跟蹤思考每一步程式很麻煩,這和其他學科一樣的,你一開始會覺得阻力如山,但是一旦你每一個例項都去用正確的思維方式去思考,很快就可以變成潛意識的活動了。

    感覺挺多人對程式設計的理解有障礙的。弄得我都想搞個培訓了~~~哈哈哈哈!!!

  • 2 # 平凡的碼農

    其實程式設計沒有你想的那麼難 但是也不簡單 開始學習時候一定要堅持 不過找工作剛剛開始相對有點難度 如果誇過這個門檻了 後面一切就沒什麼了 但是要學的很牛逼那種的話 英語一定要過關了 你可以關注我 我經常會分享我工作上一下經驗 這樣你也可以瞭解碼農了

  • 中秋節和大豐收的關聯?
  • 善人者,不善人之師;不善人者,善人之資。是什麼意思?