2013年6月25日 星期二

[Android] 一個簡單的自製 layout - SimpleCellLayout

寫Android寫了這麼久, 才想到自己沒寫過custom layout, 剛剛花了點時間(主要時間還是花在跟Android studio和gradle搏鬥)寫了一個簡單的CellLayout (還很陽春) :

https://github.com/julianshen/SimpleCellLayout

寫custom layout還蠻簡單的, 在onMeasure決定自己和child views的大小, 在onLayout時把每個child views放到適當的位置, 目前還沒加入attibrtues的支援, 所以暫時還只能寫code自己把view加進去, 另外也還沒加檢查是不是會有重疊的views, 之後再來寫

這個layout跟GridView不同, 可以不用每個格子都是同一大小, 以下範例是把畫面劃成4x4的格子, 左上角的那張圖大小是2x2, 下方則是 4x2



2013年6月21日 星期五

[Android] 圓形大頭貼 - 使用Picasso的Transformation

現在不管是Google+也好, 或是Facebook (Home), 似乎都很喜歡用圓形的大頭貼像這樣 (左上角圖形,

但在server端存的大頭照其實都是都是方形的, 所以必須抓下來後再轉畫成圓的, 最近從網路抓圖的部分, 我還蠻喜歡用Picasso

沒啥別的原因, 就是它簡單, 雖然說, 它似乎還是有一些小小問題, 不過它可以用這樣短短一行解決圖檔下載並顯示到ImageView的一連串動作:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

不過, 簡單的代價可能在其他的地方來說彈性就不高了, 不過, 做這樣一個小玩意兒的彈性倒是還有, 在Picasso中, 可以實作Transformation把下載下來的圖檔再作一次後處理, 在它的網頁有一個CropSquareTransformation的範例, 圓形的大頭貼可以視為這一個的延伸:

這邊利用了BitmapShader重畫了一張圓形的大頭貼, 出來的結果就會像是這樣:


2013年6月20日 星期四

[Android] 一閃一閃亮晶晶的BlinkLayout

Androids Do Daydream裡有提到Romain Guy要他提(大概假的吧)在layout裡面放"<blink>"可以做到view閃爍的效果而不用寫到一行code

查了一下AOSP的原始碼也的確有這東西, 它是一個躲在LayoutInflater的一個叫BlinkLayout的東西, 這樣一來就可以配合TextClock (API Level 17)來做一個閃爍的時鐘了


不過, 這樣, 是整個TextClock在閃, 而不是像一般數字鐘一樣是只有":"閃, 如果要做到只有":"在閃, 那只好把"時"跟"分"給拆開, 像這樣:

2013年6月16日 星期日

[筆記][Android Studio]Git push

本想說有直接整合了Git, GitHub是件不錯的事, 沒想到要把新project push到remote git就栽了....

Android Studio/Intellij 似乎沒介面設定remote (搜尋了半天沒發現這種答案, 啃了半天的使用手冊也沒發現), 現在如果要把既有的project給匯出到遠端的git (如bitbucket), 就得利用command line (以bitbucket 為例):

  1. 在bitbucket上create一個新的project
  2. 在Android studio選"VCS"->"Import into version control"->"Create Git repository", 這樣就可以建立一個local的repository
  3. "VCS"->"Git"->"Add to VCS"
  4. "VCS"->"Git"->"Commit File"
  5. 到command line下切換到project目錄下"git remote add origin ssh://git@bitbucket.org/xxx/xxx.git"
  6. 回到Android studio, "VCS"->"Git"->"Push"
要注意的是, 如果你已經有一個remote repository,"VCS"->"Import into version control"->"Share project on GitHub"會失敗


2013年6月15日 星期六

[筆記] Android Studio, Gradle & Native libraries

最近試用Android studio開發, 可能有些習慣被以往Eclipse慣壞了, 剛剛發現放在libs/底下的東西不像以前會被自動建置到apk內, 有點小訝異, 對jar file來說, 可能還好不算太難, 在build.gradle的dependencies內補上一筆就夠了, 但對native library (jni)那些.so檔, 就沒辦法

用這樣解決了 Google了一下, 並且在Stack overflow上找到些解法來試, 可能因為Android studio跟Gradle Android plugin還一直在變化中, 在現在這版一直沒成功, 後來小改一下成底下這樣就成功了:


原本找到的解法是pkgTask.jniDir new File('build/native-libs') , 這樣會得到
> Directory 'build/native-libs' specified for property 'jniDir' does not exist.
把"new File"改成"file"就沒問題了,不過現在一切應該都還在開發中, 未來可能會有原生的native lib 支援也不一定, 未來可能這方法也不管用了吧

2013年4月2日 星期二

[Android] 列印到Android裝置

剛剛從Chrome要列印一份文件時, 發現一件有趣的事, 在選擇印表機時, 發現我的手機也在清單當中


這怎一回事? 難道可以從電腦"列印"文件到手機?

測了一下果然是如此, 在我的手機上會多了一份pdf, 內容就是由我的電腦列印過去的, 而且是透過Google Cloud Print, 打開Cloud Print的設定, 可以看到Print Jobs的確有我剛列印過去的


這功能需要有登入Cloud Print, 並且手機也要安裝Chrome才可以

不知道實不實用, 還蠻有趣的就是了


2013年4月1日 星期一

[Android dev] JsonReader

原本在Android下解析JSON內容,  大多用JSONObjectJSONArray, 這兩個是很簡單的JSON parser, 只要將字串(String)傳入即可

不過, 這跟在用DOM解析XML是有類似的問題, 解析文件是一氣呵成, 必須要把所有內容先走過一遍, 也需要更多的記憶體來儲存, 這對於解析較大的文件是一個大問題, 必須要花費更多時間和空間, 而且如果所需要的資料就算只是整份文件中間的一小部分, 還是得先把整份文件走完, 在XML, 可以用SAX來解決這問題, 但Android要到API level 11(Honeycomb) 才新增了JsonReader這個算是JSON界的SAX的解決方案

 JsonReader類似SAX, 也是一種streaming parser, 並不用一次讀出所有字串內容, 它要的只是個Reader, 但不太像SAX屬於事件驅動(event driven)的方式, 它應該比較像token consuming, 它定義了幾類基本的JsonToken,  它也有BEGIN(END)_OBJECT, BEGIN(END)_ARRAY這種類似SAX中startElement, endElement, 但卻沒類似SAX的startDocument

解析一個JSON物件的程式碼如下:

     {username:"Bob", age: 14, sex: "m"} 
     reader.beginObject();
     while (reader.hasNext()) {
       String name = reader.nextName();
       if (name.equals("username")) {
         username = reader.nextString();
       } else if (name.equals("age")) {
         followersCount = reader.nextInt();
       } else {
         reader.skipValue();
       }
     }
     reader.endObject();
解析一個物件, 要從beginObject開始(陣列則是beginArray), endObject結束, 接著透過一個while loop一個個走過這物件內所有的token, 說實在的, 不是很好debug,  你必須要先知道下一個要處理的token是啥類別, 以上面的例子為例, 物件內第一個token是"username", 這是一個JsonToken.NAME, 因此要用nextName來處理, 搞錯了就會出錯, 還不容易知道錯哪,  而上面那例子裡的"else"也是必須的, 拿掉的話, 在endObject就會出錯, 因為這段程式並沒去處理"sex", 因此處理完sex這個名字後, 並未消化掉"m"這個值(JsonToken.STRING), 而是直接endObject, 這會產生一個IllegalStateException

為了避免用了錯誤的方式處理下一個token, 可以先用peek()來看一下下一個要處理的種類

在可讀性上, 用JsonReader寫出的並不是很好, 但它卻適合來處理大的JSON文件, 或是像Twitter Streaming API這種幾乎無止盡的

這當然也不是只有在Android上有, Google也早把這也包含到GSON去了

2013年3月21日 星期四

可以用來取代Google Reader的另一個Google產品 - Currents (潮流同步)

最近科技界比較流行的戲碼是: Google要把Google Reader給送上斷頭台了

這齣戲有點輕肥皂劇的感覺, 先是Google公布要把Reader給喀嚓了, 再來就是一堆重度使用者叫苦連天, 一堆原本吃Google reader豆腐的服務跳出來說要接手實作替代方案, 緊接著是Google reader的Product manager 在Quora上爆料Google都把人抽去做Google+, 再來就是有重量級的部落格重炮轟擊Google關掉受歡迎的東西卻拿人力去開發沒用的東西(Google+), 對於這樣的評論, 個人是認為"言重了", 我自己本身的觀點跟這些是有點相反的, 不過我的觀點不主流, 這篇也不是為了談這個, 只是先行加點小小囉嗦... :P

Google Reader停了, 對原本的重度使用者以及使用到他的服務比如說feedly, 應該是重傷不少, 對我個人而言, 影響不大, 我在幾年前早把我消耗資訊的習慣, 從Reader轉到Twitter了, 個人認為Twitter也是一個很好的消化資訊的管道

不過, 先不管Reader和Twitter...你聽過Google有一個跟Reader同質性相當高的服務叫Google Currents嗎? 這是一個在這一年內(應該是吧)的新服務(中文譯名是有點矬):


目前除了有Android版本外, iOS上也是可以找的到

跟Google Reader不同的是, 它比較像Flipboard, 事先把新聞網站分類整理好讓使用者訂閱, 乍看之下是跟Google Reader不一樣的概念, 但是, 其實Google Reader訂閱的東西也是可以轉移到這邊來的

首先, 從"新增訂閱項目"開始

拉到最下面, 可以找到你原本就在Google Reader已訂閱的項目, 這時候你就可以把他們一個個加進來了


那可不可以加自定的RSS呢? 也不難, 這邊示範了怎樣加我自己Flickr的RSS, 搜尋"flickr julianshen", 馬上就找到它了, 我甚至還不用跑到Flickr網頁去找到那個RSS

再做另一個實驗, 搜尋我的名字"julianshen", 不但我的Flickr, 我的blog, 甚至是我的GitHub, Youtube, 都跑出來可以讓你去訂閱, 而且搜尋速度, 還蠻快的

當然也不是沒有缺點:

  1. 目前只有Android, iOS 版本並無PC或Web版本, 當然更無其他3rd party軟體
  2. 加進去的RSS都會被自動歸類, 大多被歸類在"資訊提供", 有些會被歸類的其他類別(比如說某些科技公司的新聞的RSS可能會被自動歸類到科技類), 沒辦法像Google Reader一樣自定目錄來分類, 也不能修改分類
  3. 沒辦法直接跟瀏覽器配合
不過這些好像對Google來說也不是啥複雜難做的吧

有兩個同質性那麼高的服務, 關掉其中一個也還蠻合理的啦, 賴到Google+頭上, 好像也有點無辜 XD




2013年3月13日 星期三

Twitter 1.1 API的Search不再是不需要Authentication的了

以往Twitter的search API是不需要任何認證, 也不需要設定啥App ID或啥consumer key的, 不過, 在API 1.1之後, 這就改了

因為1.1, search也列入rate limit的追蹤囉, 所以使用search API也要做認證(Authentication), 但由於search api的使用情境, 不見得一定需要使用者登入, 有些做資料分析的應用也有可能會用到, 所以強制用OAuth就有點不是很合理, 所幸, 除了用OAuth以外, 這類的API也可以使用Application-only authentication:


  1. 首先必須要用Basic Auth的方式取得token, 用consumer key當user name, consumer secret當password去呼叫/oauth2/token的API
    1. 使用POST
    2. 必須要有grant_type=client_credentials
  2. 成功的話就會得到access_token (注意token type為bearer)
  3. 使用這個token去呼叫API (search或其他不需要user login的API)
    1. 把token加在HTTP的Authentication header (像是: Authorization: Bearer AAAAAAAAAAAAAAAA )
    2. 一定要走SSL (https), 如果是非SSL會碰到"Bad Authentication data"的錯誤
以下是Sample code (使用Go):




2013年2月15日 星期五

[Mac] 在Qt中使用自訂的Info.plist

iOS和Mac OS的應用程式裡都有個info.plist放置著應用程式相關的設置, 用Qt開發Mac應用程式時, 這個檔是在編譯時自動產生, 因此幾乎是固定內容

但還是有需要在info.plist內加入額外的內容, 比如說Retina display的支援(NSHighResolutionCapable), 預設並沒有, 因此還是有需要做自訂的info.plist

作法並不難, 在專案檔(通常是 xxxx.pro)內加入下面的內容:
mac {
QMAKE_INFO_PLIST = XXXX.plist
}

mac {}內指得是, 這些內容只有針對mac os才有效, 而XXXX.plist則是你的Info.plist的範本檔名, 這個檔跟專案檔放在同一個目錄

XXXX.plist的內容則像這樣:

跟一般的Info.plist其實是一樣的, 我在這範例裡面加上了"NSHighResolutionCapable", 其餘都跟原先自動產生的內容是差不多的, 除了幾個關鍵內容用變數取代, 這邊變數都是以"@"包起來的, 比如說"@ICON@"就是應用程式的圖示

重新做一次qmake後, 下次編譯的Info.plist便會以這個檔案為範本產生了

2013年2月9日 星期六

讓Eclipse支援Retina Display

前陣子買了一台Retina display的mac book pro, 興沖沖的把一切都設定好後, 正很滿足的想要用這漂亮的畫面開始工作時, 一打開Eclipse後, 一整個傻眼, 字變糊變鋸齒, 看來Eclipse對Retina display並沒有很好的支援, 查詢過各方資料後, 所幸還有救(不然就想投奔到別的IDE去了)

1. 找到Eclipse, 在上面按右鍵選"顯示套件內容"

2. 找到Info.plist, 用Xcode開啟


3. 新增一個"High Resolution Capable", 並將其設成"YES"


2013年1月22日 星期二

[Android][筆記] BitmapShader

http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
這篇文章裡面使用到了BitmapShader做圓角的效果, 使用這方法, 如果drawRect的大小比原先大的話, 會根據Shader.TileMode來畫出不同的效果:

Shader.TileMode.CLAMP (效果: 尾端拉長) --

Shader.TileMode.MIRROR (效果: 鏡射) --

(畫面是我的小作業 - iTunes U for Android)










 

2012年12月27日 星期四

[iOS] 利用Smart App Banners在網頁上推廣Native App

起初先在Flickr網頁注意到這個:


按下open就會直接帶你到App store下載Flickr App, 這就是iOS6開始有的Smart App Banners, 覺得頗有趣的, 就去看了原始碼查了一下作法:

以上這是Flickr的HTML裡面的, 作法很簡單, 就只是在HTML內放個"apple-itunes-app"的meta tag, 指定app-id和參數(非必須)

Android應該也要加個這東西才對呀.....

好像該寫個開箱文 - 白蝴蝶

等了那麼久, 蝴蝶終於飛來了, 實在有點歷經波折呀~~~



這不是我第一支預購的自己公司的產品, 第一支是給老婆的Sensation, 這算第二支, 為啥堅持要預購, 還追那麼勤勞? 1. 自己用過一段時間, 這的確是好產品! 2. 從預購開始, 才能真正體驗完整的使用者體驗呀... (剛掰的) 3. 拿好手機在街上走不用遮遮掩掩的....

不過這次還真一波三折, 經歷了貨等不到, 換了顏色(本想買紅的), 又拿到亮點機, 都已經跟店員打熟了....


外盒, 蠻簡潔的, 不過少了以前HTC一貫的塗鴉風格設計, 有一點不習慣, 還是喜歡塗鴉風, 比較可愛

本來想買紅的, 之前用過一陣子紅的, 覺得紅的很搶眼頗漂亮的, 但紅的實在缺的兇, 只好跟店員說我紅白都可(我實在沒辦法喜歡黑的), 本想說白不是整支純白並沒紅的來的好看, 但拿上手後, 反而覺得我喜歡白的勝過紅的呀


去專賣店預購就是為了這個呀...送皮套的刮刮卡呀.... 



2012年11月25日 星期日

[開箱] 今年的生日禮物 Tissot PRC 200 機械錶

去年的生日禮物是耳機 (AKG K-701) , 今年則是因為原本戴的FOSSIL錶打球的時候壞了,修又差不多買新的一半以上的錢(壞的好嚴重呀), 備用的錶的錶帶又常常脫落戴的不舒服, 所以就打算換隻錶

本來是看SEIKO, CITIZEN, 看金城武跟王力宏代言看起來蠻帥的, 日本錶功能又多, 科技感濃厚, 就有點感興趣, 不過直到昨天, 跑去看007電影Skyfall, Bonds戴的Omega也蠻帥的呀, 不過自己平常對錶沒啥研究, 不知道, 這還真是我買不起的高貴, 買不起Omega還是繼續跑去專櫃看了SEIKO, CITIZEN, 實際上看了實物, 還是失望了, 這不是我想要的型, 才發現我喜歡的並不是這麼濃的科技感, 而是比較古老一點的機械

再逛了一下瑞士的錶款, 還真一個比一個高貴, 好像只有TISSOT是外型跟價位還是我可以接受的, 所以今天就找了老婆, 小遠跟我去敗了這隻 - TISSOT PRC 200機械錶, 這還真是我戴過最貴的(羞), 也是第一隻機械錶

紅黑色的外盒:

躺在盒內的樣子...其實這是偽開箱啦...為了拍照再擺回去的 XD

錶面很單純, 沒多餘的圈圈(?!), 我還蠻喜歡那秒針的, 上面有個T, 其實我更喜歡BALL的指針設計, 不過那在預算外了, 白色錶面銀色框是我喜歡的, 黑錶面跟玫瑰金就不是我的菜了... ^^

透明的背面看的到一些機械錶的結構

戴在手上的樣子

此外還有送一條贈品, USB 線, 不過這種線我有好多條了.... XD 

2012年11月13日 星期二

[Go筆記] UUID package

自己想做的東西可能需要一個UUID的產生器, 找了一下既有的packages跟網路上的, 好像沒一個自己滿意的, 所以就自己從java.util.UUID po過來

Source在此: https://github.com/julianshen/GoUUID

目前只implement RFC 4122 Version 4

Sample:

2012年11月7日 星期三

[node.js] 在heroku上用bower管理前端第三方元件

在做web applications時,或多或少都會使用到像是jQuery, bootstrap這類的第三方元件,使用已經host在既有CDN 的版本(比如說google的)是一個不錯的方法,但不是每一種都有這類方案,一個個從各網站下載回本地端又不是那麼容易管理,bower就是為此出現的,bower是一個類似npm的軟體,由Twitter所開發出來且是開放原始碼,所不同的是,npm是管理node.js相關的套件,但bower是管前端的

舉一個例子,你可以利用bower來安裝jQuery :
bower install jQuery
bower會把jQuery 安裝到"components/jQuery" 目錄裡

在npm , 你可以把所有相關的模組設定在package.json中,這樣就不用一個個下"npm install mypackage"這樣的指令了,bower也有類似的設計,只是為了避免跟package.json造成混淆它採用的檔名是component.json,內容跟package.json差不多:
{
    dependencies: {
      "JQuery": "*"
    }
}
在Heroku deploy node.js app有個很方便的地方是,當你做git push 後,它會根據package.json自動幫你安裝相關的node.js 模組,但不幸的是它並不支援bower,只支援npm

還好Heroku很有彈性,可以藉由buildpack來自己加這部份

buildpack API其實還蠻簡單的, 基本上只要準備三支shell script:
  • bin/detect
  • bin/compile
  • bin/release
大部分的東西, 大多在"bin/compile"裡完成的

自己做的buildpack也只要放github, 然後將自己app的buildpack指定到這來即可 (使用heroku toolbelt):
  • 新建的程式使用自己的buildpack: 
    heroku create myapp --buildpack https://github.com/heroku/heroku-buildpack-ruby
  • 既有的程式更換buildpack:
    heroku config:add BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby
當然, 不需要重頭建立自己的buildpack, Heroku官方的buildpack都有open source在github上, 如Node.js buildpack, 所以只要fork出來修改即可, 因此我從Node.js buildpack fork出一個新的buidlpack, 主要的修改是:

  1. 安裝bower
  2. 找出所有的component.json並用"bower install"安裝套件
本想說 "1" 應該蠻簡單的, 因為bower也是用node.js開發的, 應該只要用npm install bower就搞定了, 但事實是, 這樣會碰壁, 因為bower採用了lodash , lodash跟Heroku的npm似乎八字不合, 安裝過程到lodash的post-install就會失敗, 也沒明顯的錯誤, 只說這應該是套件問題, 而去查了lodash, 也有人報過類似的issue, 但作者卻以lodash沒問題應該是npm的問題把這issue給關了(鬼打牆?), 但:
  • 自己電腦上安裝bower或lodash都沒問題
  • 在自己的package.json加上lodash, deploy到Heroku也一樣掛
  • 在package.json裡設定engine裡的npm版本到最新的1.1.65(跟自己電腦上一樣版本), 也一樣不行

那...就不得不懷疑是npm問題了, 查了原本buildpack寫的, Heroku的node.js和npm其實是拿他們自己放在S3的binary package來安裝的, 可疑!

因此就使用了下一招 - 用npm來裝npm

用Heroku系統內的npm來裝npm是可行的, npm install npm的結果是, 會有一份最新的npm被安裝到node_modules底下, 可以用"node_modules/.bin/npm"來呼叫這版本, 因此就加上了:
node_modules/.bin/npm install bower
Bingo! 這樣可行, bower一樣被安裝到 node_modules/.bin底下, 加上 "2"的邏輯到"bin/compile"後就大功告成了,

有修改的部份只有"bin/compile", 比對一下commit history就可以知道我修改過啥, 中間有做了很多實驗, 所以有不少垃圾commits, 可以忽略

如果有需要這版本buildpack, 也歡迎利用:

https://github.com/julianshen/heroku-buildpack-nodejs




2012年11月5日 星期一

[node.js] 用npm安裝放在github上的module

剛剛為了想要做一個東西, 需要用到Flickr API, 本想要拿Passport.js來處理Flickr OAuth的部份,但卻發現, FLickr Strategy的部份不但年久, 而且permission這部份居然是hard code "read", 由於我想做的東西是要write, 其實是可以靠overwrite "userAuthorizationURL"來達到這目的, 不過這樣不好看, 所以就乾脆自己fork一版來改 (Github真是好物來改)

改完後的一個問題是, 原本可以用"npm install passport-flickr"來安裝這module, 但由於我fork出來的並未註冊在npm, 所以就得用另一個方式:
npm install git://github.com/julianshen/passport-flickr.git#master
這方式是直接把git url給npm, 不過要deploy上heroku就麻煩了, 還好寫在package.json裡也是沒問題的
"dependencies": {    "passport-flickr": "git://github.com/julianshen/passport-flickr.git#master"}
這還蠻簡單的, 只是把原先寫version的地方換成git URL就好, 在Heroku上也是沒問題的

題外話: 剛deply到heroku上時發現express 3.0.1無法安裝, 原因是我忘了在package.json裡註名我node.js的版本, 這種狀況下, Heroku會自動幫你挑v0.4.7版

2012年11月3日 星期六

竹北。梨頭山

今天有點時間, 想說出門拍個照, 在網路上稍微查了一下看看有沒啥制高點可以拍高鐵,平常從底下拍高鐵拍的有點無聊了, 所以就找到了梨頭山, 反正也離家不遠 到梨頭山, 可以從文山國小有個登山步道上去

 
View Larger Map

住這邊這麼久了, 說真的, 還沒來過這, 碰了運氣找到了入口, 感覺好像還真是個人煙罕至的地方

DSC04718

太久沒啥運動, 這坡度爬起來還真有點喘, 也不知道該爬多高才可以看到高鐵, 其間曾一度在樹林縫隙看到了軌道, 不過這並不是最佳位置, 到了山頂上, 果然名不虛傳呀, 高鐵站周邊景色一覽無遺

DSC04957

在這邊用長焦段的鏡頭並不難捕捉到高鐵的身影, 不過新買的反射鏡實在令人失望, 不但不好對焦畫質也差, 只好用super takumar 135mm這隻俗又好用的鏡頭


DSC04917
DSC04889

這邊的景致還不錯, 而且離我家非常的近, 可以俯瞰高鐵站

下次有機會再來去湖口另一個拍攝地點看看好了....

2012年11月2日 星期五

[Go 筆記] Type, method, and interface

"Go was born out of frustration with existing languages and environments for systems programming."
Go 是為了作為一個系統語言(systems programming language)而存在的, 它跟天下知名的C語言有同一個父親 - Ken Thompson , 作為一個系統語言, 它並不是直譯式語言, 也非跑在虛擬機(virtual machine)上, 而是貨真價實的像C一樣是先編譯(compile), 而且也是屬於strong and static type的語言, 這表示, 變數型別是預先宣告/決定的, 而且是不能半路變更的, 變數可以像這樣宣告:
var StrVariable string 
var IntVariable int
這邊跟C, Java之類的語言不同的地方是, 型別定義是在後面不是放前面, 剛看到時我以為我會不習慣, 但卻花沒很多時間就適應了, 可能是我在很早以前寫過PASCAL的關係吧, PASCAL也是類似的寫法

但, Go其實還引入了一些dynamic language的特性, 因此在Go內也可以看到未經上面類型的宣告, 就直接指定的敘述, 像是:
strVariable2 := "Hello Go"
這敘述並不代表Go也有dynamic typed的設計, 其實這設計是同時結合了宣告跟指定(assignment), strVariable2並不是沒有型別或動態型別, 因為":="的關係, 使得strVariable2一開始就被宣告成後面值的型別, 因此上面那行跟下面一樣:
var strVariable2 string
strVariable2 = "Hello Go"
同理, "intVariable2 := 1"這敘述表示intVariable一開始就被宣告成整數(因為1是整數), 所以它還是一個strong typed的設計, 這邊比較要注意到的一個陷阱是"="和":=", 在已宣告過型別的變數, 是用正常的"="來指定值, 但在未宣告的變數, 必須要用 ":="

你不能做的是... "strVariable2 = 1", 因為strVariable2在前面已經":="被宣告成字串(string)

在Go, 你一樣可以自定型別, 結構(struct)
type MyString string
type User struct {
    Uid int
    Name string
之後, 你就可以用MyString或是User來宣告變數, 像是
var M1 MyString
var User1 User
User2 := User {1, "julian"}
"type MyString string"有點像是C語言的typedef, 可以讓你以另一個型別(MyString)來替代原本的型別(string), 但它其實還有個妙用, 在後面會再提到

Go是一個functional programming language, 所以它並沒有物件導向觀念

沒有"類別"(class), 沒有物件/實體(object/instance), 但, 它卻有"方法"(method)和"介面"(interface), 聽起來有點四不像, 但其實這部份還蠻有趣的

先說到"方法"(method), 在Go, 你可以為你的型別設計一個"方法", 像是這樣:
func (u *User) Hi() {
    fmt.Printf("Hi! I'm %s. The %d user.\n", u.Uid, u.Name)
}
這邊"Hi()"就是屬於"User"的一個方法, 呼叫"User2.Hi()"即可執行它, 方法跟一般的函數一樣, 所不同的是, 前面多了一個"(u *User)" 以這例子來說, 這邊就是定義了"Hi()"的母體是 *User (*是指標- pointer的意思, 就不在這邊解釋)

這邊有趣的地方是, 你可以為任何自定型別創造"方法", 包含函數(function), 這在"net/http"內就可以找到類似的應用:



在這例子中, HandlerFunc有一個ServeHTTP的方法, 但HandlerFunc本身其實是一個function

"介面"(interface)也是一個蠻妙的東西, 在Java裡, interface必須要宣告"實作", 亦即"class MyImpl implements MyInterface", 也就是你必須指定某個class實作了某個interface

但在Go, 則是很不一樣, 在Go裡, 你可以宣告一個"介面"(interface) 像是
type MyInterface interface {
    Foo()
}
但你不需要宣告某個型別"實作"了這個interface, 在Go, interface反而比較有"暗示"(imply)的意味, 也就是, 下面的例子, 不用任何宣告, 你可以把MyString自動當成它也可以是一個MyInterface:
func (s MyString) Foo() {}
因為在MyInterface的定義中, 它含有一個"Foo()", 當你替MyString宣告了一個"Foo()"的方法時, 就自動讓MyString變成了一個實作了MyInterface的型別

下面用一個比較完整的例子來總結:


在這例子中, "CallFoo(MyInterface)"接受一個MyInterface的參數, 並執行它"Foo()"的方法, 由於"Aa"(字串)和"MyHandler"(函數)都是有一個"Foo()"的方法, 所以他們都可以被當做MyInterface作為參數, 同理, 回到前一個HandlerFunc範例, HandlerFunc其實也可以被當做Handler這個interface來使用, 在"net/http"的API中就是用到了這樣一個技巧