中國電動車產業趨於成熟,2016年車用鋰電池後市看俏

今年全球電動車市場整體表現不俗,主要歸功於中國市場政策支持而推動,前景持續看好。2015年中國電動車銷售量達13萬輛水準,年成長高達20%,而在整體銷售量中純電動車即占有64%。

TrendForce旗下綠能事業處EnergyTrend分析師呂理舜表示,中國電動車的穩健發展帶動了鋰電池新一波高峰,應用主要區分為圓柱型鋰電池(小型電池)及方型鋰電池(大型電池),在過往市場混屯階段時於各種車輛中混用,但到了2016年電池在特定車種的搭配性將更為明確。

此外,預期明年車用鋰電池也將因電動車熱銷加持而出現短缺,圓柱型電池或方型電池後勢看俏,帶動電動車電池出現少見的漲價聲浪。隨著補貼降低與車輛技術成熟,中國將走向更細緻與明確的發展策略。

TrendForce預測2016年中國鋰電池於電動車產業中重要趨勢如下:

中國政府補貼力道逐漸放緩,2016年電動車產業逐漸收斂

中國電動車產業漸趨成熟,中國政府也決定逐漸免除單純給予車廠的價格補貼,轉向針對過去較為不足的周邊配套進行強化,包括研發、生產、購買和充電環境等多層面相,邁向更成熟的完整配套。明年除了在購買上免徵牌照稅外,另增輕型電動車的購買補助辦法;充電方面也提供寬鬆的融資擔保條件,讓進度落後的充電設施能夠跟上電動車銷售的成長性。呂理舜指出,此一措施也將使非主流電動車供應者、或剛要開始投入的品牌車廠,逐步被市場所淘汰,從百花爭鳴進階到汰弱扶強的階段。

圓柱型電池焦點轉向汽車和微型車市場

對比在筆記型電腦市場的衰退,圓柱型電池焦點已明顯轉往中國電動車。以車種搭配來看,圓柱型電池的主要使用對象為特斯拉,但隨著中國微型車興起,也讓圓柱型電池在中國成為搶手貨,包括比克、力神、比亞迪等主要廠商產能皆滿載,來年的擴增產能計劃也持續規劃中。

6~8米輕型電動客車將以方型鋰電池為主

近年興起的6~8米輕型電動客車也是另一關注焦點,EnergyTrend統計指出,自2013年中國首次納入規廣補貼範圍後,掛牌量突破6000輛,主要購買客戶包括汽車租賃公司、及公務/商務客戶。

除了國家補貼的30萬人民幣外,成長主要動能也包括各地方的補助,促使6~8米輕型電動客車購買成本可低於傳統客車,部分補貼較高的地區甚至可達零成本。目前供應商如合肥國軒、新能源等,都開始因6~8米中小型電動客車需求提升,而推升應用的方型電池供應量,也帶動整體價格水漲船高。EnergyTrend統計,今年下半年方型電池已有約5%的漲幅,2016年也將維持在5%的價格提升。

 

3Q15 鋰電池銀級會員報告

消費型應用

  • 電池芯供需變化
  • 國際、中國電池的產能動態
  • 圓柱、方型與高分子的價格與供需狀況
  • 未來的三種電池芯發展走向

動力型應用

  • 新出台的的新能源車補助措施
  • 低速電動車(微型車)、乘用車與輕型客車的崛起

如果您想要瞭解更多關於EnergyTrend 鋰電池產業報告的細節,以及會員報告的說明,請點這裡或歡迎聯繫:

Joanne Wu (Taipei)

joannewu@trendforce.com

+886-2-8978-6488  ext. 912 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

實現中國新能源汽車大發展,還需解決4大難題

一系列政策推出後,新能源汽車進入了快速發展階段,據數據統計,前10個月,我國新能源汽車產銷分別增長了2.7倍和2.9倍,而且目前私人購買新能源汽車增長快速。然而,制約新能源汽車發展的因素逐漸顯現。  
1.充電基礎設施建設滯後   Interbrand公司的孟祥峰博士表示,到2014年底全國的示範城市推廣的新能源汽車數量是9.1萬輛,但是充電樁只有3.1萬個,充電樁和新能源車的比例明顯不足。   11月18日,國家發展改革委等四部門聯合發佈《電動汽車充電基礎設施發展指南(2015~2020年)》表示,到2020年,新增集中式充換電站超過1.2萬座,分散式充電樁超過480萬個,以滿足全國500萬輛電動汽車充電需求。  
2.動力電池產業佈局系統性不足   從去年下半年開始,隨著整車銷量的快速增長,動力電池產品供不應求,限制了整車的生產和推廣。廣汽集團總經理曾慶洪表示,國家要求2025年電池的能量密度要達到每公斤350瓦時,現在是150~250瓦時左右。   清華大學教授歐陽明高透露,我國今年1-9月份乘用車電池的用量超過了61億瓦時,預計全年至少會超過110億瓦時,預計2020年有可能達到1000億瓦時。同時,歐陽明高表示,我國今年電池的投資大概接近1000億元,已有和在建的產能投資也超過了800億元,預計明年下半年電池供需總量基本平衡。  
3.整車技術有待提升   廣州日報記者在第二屆廣州國際電動汽車展覽會上看到,目前我國自主推出的電動車在車型方面仍有待提升,不少電動車的外形與傳統燃油車各種“靚”形成較大反差。一對夫婦看了某品牌的電動汽車後表示,開這種車確實是綠色出行,但很卡通的外形用來見商務客戶就不太合適了。  
4.過分依賴補貼   清華大學教授歐陽明高表示,目前國內新能源汽車存在的問題之一就是補貼的依賴還比較嚴重,補貼對整個市場產生的作用應該說過大,需要進行合理化。他認為,尤其是6~8米的客車,目前來說補貼的合理性有待完善。   中國國際貿易促進委員會汽車行業分會會長王俠也表示,我國的汽車市場規模龐大,全產業鏈發展的自然基礎,但是能否實現全產業鏈的協調發展,其中政策的制定是系統的工程,沒有補貼不行,補貼時間過長也不行。王俠表示,企業的當務之急是,實現核心技術的突破,降低成本,提高產品的安全性和可靠性,改變單純依靠補貼的盈利模式。   資料來源:廣州日報

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

js數組方法大全(上)

# js數組方法大全(上)

記錄一下整理的js數組方法,免得每次要找方法都找不到。圖片有點多,注意流量,嘻嘻!

本期分享

  • join()
  • reverse()
  • sort()
  • concat()
  • slice()
  • splice()
  • push()
  • pop()
  • unshift()
  • shift()
  • toString()
  • toLocaleString()

下期分享

  • forEach()
  • map()
  • filer()
  • every()
  • some()
  • reduce()
  • reduceRight()
  • indexOf()
  • lastIndex()

join() —>用指定分割符將數組轉為字符串

  • 使用熱度:常用
  • 是否改變原始數組:否
  • 返回:按指定字符串進行分割后的字符串
  • 參數:
參數位置 參數類型 是否必選 作用
1 string 將數組轉為字符串,並用指定字符進行分割
  • 說明:不傳入參數的話,將數組元素轉為字符串,並用逗號進行分割
  • 實例如下:
var log=console.log;
var a=[1,2,3];
log(a.join());
log(a.join(" "));
log(a.join(""));
var b = new Array(10);
log(b.join('-'))

reverse() —>將數組元素顛倒

  • 使用熱度:不常用
  • 是否改變原始數組:是
  • 返回:將數組中的元素顛倒順序,返回逆序的數組。
  • 參數:無
  • 實例如下:
var log=console.log;
var a=[1,2,3];
a.reverse();
log(a);

sort() —>按指定要求對數組進行排序

  • 使用熱度:不常用
  • 是否改變原始數組:是
  • 返回:返回排序后的數組
  • 參數:
參數位置 參數類型 是否必選 作用
1 function 函數的兩個參數分別是數組對應的兩個元素,函數返回大於0,則第一個參數排在前面。函數返回一個小於0的數,則第一個參數排在後面。函數返回0,代表這兩個參數的排序無關緊要。
  • 說明:不傳入參數的時候,會將數組元素按字母表排序並返回,如果元素非字符串,將會臨時轉為字符串進行比較,如果元素中有undefined,則會甩到最後面。
  • 實例如下:
var log=console.log;
var a=[,'a','b',true];
a.sort()
log(a)
var b=[3,7,4,4,2]
b.sort(function(i,j){
    return i-j
})
log(b)

concat() —>將數組和其他元素合併返回新的數組

  • 使用熱度:常用
  • 是否改變原始數組:否
  • 返回:返回一個合併了的新數組
  • 參數:
參數位置 參數類型 是否必選 作用
1+ * 將原始數組的每個元素和每個參數合併到一個新的數組並返回
  • 說明:如果參數中有數組,這將數組拆分合併,而不是直接合併數組本身,但是不遞歸扁平化數組的數組。
  • 實例如下:
var log=console.log;
var a=[1,2,3];
var b=a.concat(4,5,6,[7,8,[9,10]]);
log(a);
log(b);

slice() —>截取數組一段進行返回

  • 使用熱度:常用
  • 是否改變原始數組:否
  • 返回:一個數組的一個片段或者子數組
  • 參數:
參數位置 參數類型 是否必選 作用
1 number 用來指定要返回的數組片段開始位置
2 number 用來指定要返回數組的結束位置,如不指定,則表示返回到數組末尾
  • 說明:如果參數是一個負數,則從數組倒數開始和結束。
  • 實例如下:
var log=console.log;
var a=[1,2,3,4,5,6];
var b =a.slice(1)
log(b)
var c=a.slice(1,-1)
log(c)
var d=a.slice(-3,-1)
log(d)

splice() —>刪除或者替代數組指定區域

  • 使用熱度:經常用
  • 是否改變原始數組:是
  • 返回:刪除的數組,如果未刪除則返回空數組
  • 參數:
參數位置 參數類型 是否必選 作用
1 number 用來指定插入或者刪除的起始位置
2 number 指定要刪除或者替代數量,如果不指定,這會刪除所有
3+ * 替代的元素
  • 實例如下:
var log=console.log;
var a=[1,2,3,4,5,6,7,8,9];
var b=a.splice(8);
log(a);
log(b);

var c=a.splice(5,1);
log(a);
log(c);

var d=a.splice(2,2,'a',[33,44]);
log(a);
log(d)

push() —>在數組元素後面增加元素

  • 使用熱度:頻繁使用
  • 是否改變原始數組:是
  • 返回:新數組的長度
  • 參數:
參數位置 參數類型 是否必選 作用
1+ * 在數組末尾增加一個或多個數組元素
  • 說明:在數組末尾增加一個元素
  • 實例如下:
var log=console.log;
var a=[1,2,3];
var b=a.push()
log(a)
log(b)

var c=a.push(4,5,6);
log(a)
log(c)

pop() —>刪除數組元素後面的一個元素

  • 使用熱度:不常用
  • 是否改變原始數組:是
  • 返回:被刪除的數組
  • 參數:無
  • 說明:刪除數組末尾的一個元素
  • 實例如下:
var log=console.log;
var a=[1,2,3,4,5,6];
var b=a.pop()
log(a)
log(b)

unshift() —>在數組前面增加元素

  • 使用熱度:常用
  • 是否改變原始數組:是
  • 返回:新數組的長度
  • 參數:
參數位置 參數類型 是否必選 作用
1+ * 在數組頭部增加一個或多個數組元素
  • 說明:當使用多個參數調用unshift方法的時候它的行為令人驚訝。參數是一次性插入的(就像splice方法),而非一次一個插入。這意味着最終的數組中插入的元素的順序和他們在參數列表中的順序一致。而假設元素是一次一個的插入。他們的順序應該是反過來的。
  • 實例如下:
var log=console.log;
var a=[1,2,3];
var b=a.unshift()
log(a)
log(b)

var c=a.unshift(4,5,6);
log(a)
log(c)

shift() —>刪除數組第一個元素

  • 使用熱度:不常用
  • 是否改變原始數組:是
  • 返回:被刪除的數組
  • 參數:無
  • 說明:刪除數組末尾的一個元素
  • 實例如下:
var log=console.log;
var a=[1,2,3,4,5,6];
var b=a.shift()
log(a)
log(b)

toString —>將數組轉為字符串

  • 使用熱度:常用
  • 是否改變原始數組:否
  • 返回:數組字符串
  • 參數:無
  • 說明:輸出不包括方括號或者其他任何形式的包裹數組值的分隔符;此方法與不使用任何參數調用join方法返回的字符串一樣。
  • 實例如下:
var log=console.log;
var a=["a",2,{"b":"c"},["d"]];
var b=a.toString()
log(a)
log(b)

toLocaleString() —>將數組使用本地化的方式轉為字符串

  • 使用熱度:不常用
  • 是否改變原始數組:否
  • 返回:
  • 參數:
參數位置 參數類型 是否必選 作用
1 string/array 縮寫語言代碼(BCP 47 language tag,例如:cmn-Hans-CN)的字符串或者這些字符串組成的數組
2 string/object 對字符串或數組處理的方式
  • 說明:在舊的瀏覽器實現中,會忽略這兩個參數,使用的語言環境和返回的字符串的形式完全取決於實現方式。
  • 實例如下:
var log=console.log
var a = [111,222,333];
var b=a.toLocaleString('ar-EG')
var c=a.toLocaleString('zh-Hans-CN-u-nu-hanidec')
log(a);
log(b);  
log(c);  

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

Uber Go 語言編碼規範

Uber Go 語言編碼規範

是一家美國硅谷的科技公司,也是 Go 語言的早期 adopter。其開源了很多 golang 項目,諸如被 Gopher 圈熟知的 、 等。2018 年年末 Uber 將內部的 開源到 GitHub,經過一年的積累和更新,該規範已經初具規模,並受到廣大 Gopher 的關注。本文是該規範的中文版本。本版本會根據原版實時更新。

## 版本

  • 當前更新版本:2019-11-13 版本地址:
  • 如果您發現任何更新、問題或改進,請隨時 fork 和 PR
  • Please feel free to fork and PR if you find any updates, issues or improvement.

目錄

介紹

樣式 (style) 是支配我們代碼的慣例。術語樣式有點用詞不當,因為這些約定涵蓋的範圍不限於由 gofmt 替我們處理的源文件格式。

本指南的目的是通過詳細描述在 Uber 編寫 Go 代碼的注意事項來管理這種複雜性。這些規則的存在是為了使代碼庫易於管理,同時仍然允許工程師更有效地使用 Go 語言功能。

該指南最初由 和 編寫,目的是使一些同事能快速使用 Go。多年來,該指南已根據其他人的反饋進行了修改。

本文檔記錄了我們在 Uber 遵循的 Go 代碼中的慣用約定。其中許多是 Go 的通用準則,而其他擴展準則依賴於下面外部的指南:

所有代碼都應該通過golintgo vet的檢查並無錯誤。我們建議您將編輯器設置為:

  • 保存時運行 goimports
  • 運行 golintgo vet 檢查錯誤

您可以在以下 Go 編輯器工具支持頁面中找到更為詳細的信息:

指導原則

指向 interface 的指針

您幾乎不需要指向接口類型的指針。您應該將接口作為值進行傳遞,在這樣的傳遞過程中,實質上傳遞的底層數據仍然可以是指針。

接口實質上在底層用兩個字段表示:

  1. 一個指向某些特定類型信息的指針。您可以將其視為”type”。
  2. 數據指針。如果存儲的數據是指針,則直接存儲。如果存儲的數據是一個值,則存儲指向該值的指針。

如果希望接口方法修改基礎數據,則必須使用指針傳遞。

接收器 (receiver) 與接口

使用值接收器的方法既可以通過值調用,也可以通過指針調用。

例如,

type S struct {
  data string
}

func (s S) Read() string {
  return s.data
}

func (s *S) Write(str string) {
  s.data = str
}

sVals := map[int]S{1: {"A"}}

// 你只能通過值調用 Read
sVals[1].Read()

// 這不能編譯通過:
//  sVals[1].Write("test")

sPtrs := map[int]*S{1: {"A"}}

// 通過指針既可以調用 Read,也可以調用 Write 方法
sPtrs[1].Read()
sPtrs[1].Write("test")

同樣,即使該方法具有值接收器,也可以通過指針來滿足接口。

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

//  下面代碼無法通過編譯。因為 s2Val 是一個值,而 S2 的 f 方法中沒有使用值接收器
//   i = s2Val

中有一段關於 的精彩講解。

零值 Mutex 是有效的

零值 sync.Mutexsync.RWMutex 是有效的。所以指向 mutex 的指針基本是不必要的。

Bad Good
“`go mu := new(sync.Mutex) mu.Lock() “` “`go var mu sync.Mutex mu.Lock() “`

如果你使用結構體指針,mutex 可以非指針形式作為結構體的組成字段,或者更好的方式是直接嵌入到結構體中。
如果是私有結構體類型或是要實現 Mutex 接口的類型,我們可以使用嵌入 mutex 的方法:

“`go type smap struct { sync.Mutex // only for unexported types(僅適用於非導出類型) data map[string]string } func newSMap() *smap { return &smap{ data: make(map[string]string), } } func (m *smap) Get(k string) string { m.Lock() defer m.Unlock() return m.data[k] } “` “`go type SMap struct { mu sync.Mutex // 對於導出類型,請使用私有鎖 data map[string]string } func NewSMap() *SMap { return &SMap{ data: make(map[string]string), } } func (m *SMap) Get(k string) string { m.mu.Lock() defer m.mu.Unlock() return m.data[k] } “`
為私有類型或需要實現互斥接口的類型嵌入。 對於導出的類型,請使用專用字段。

在邊界處拷貝 Slices 和 Maps

slices 和 maps 包含了指向底層數據的指針,因此在需要複製它們時要特別注意。

接收 Slices 和 Maps

請記住,當 map 或 slice 作為函數參數傳入時,如果您存儲了對它們的引用,則用戶可以對其進行修改。

Bad Good
“`go func (d *Driver) SetTrips(trips []Trip) { d.trips = trips } trips := … d1.SetTrips(trips) // 你是要修改 d1.trips 嗎? trips[0] = … “` “`go func (d *Driver) SetTrips(trips []Trip) { d.trips = make([]Trip, len(trips)) copy(d.trips, trips) } trips := … d1.SetTrips(trips) // 這裏我們修改 trips[0],但不會影響到 d1.trips trips[0] = … “`

返回 slices 或 maps

同樣,請注意用戶對暴露內部狀態的 map 或 slice 的修改。

Bad Good
“`go type Stats struct { mu sync.Mutex counters map[string]int } // Snapshot 返回當前狀態。 func (s *Stats) Snapshot() map[string]int { s.mu.Lock() defer s.mu.Unlock() return s.counters } // snapshot 不再受互斥鎖保護 // 因此對 snapshot 的任何訪問都將受到數據競爭的影響 // 影響 stats.counters snapshot := stats.Snapshot() “` “`go type Stats struct { mu sync.Mutex counters map[string]int } func (s *Stats) Snapshot() map[string]int { s.mu.Lock() defer s.mu.Unlock() result := make(map[string]int, len(s.counters)) for k, v := range s.counters { result[k] = v } return result } // snapshot 現在是一個拷貝 snapshot := stats.Snapshot() “`

使用 defer 釋放資源

使用 defer 釋放資源,諸如文件和鎖。

Bad Good
“`go p.Lock() if p.count < 10 { p.Unlock() return p.count } p.count++ newCount := p.count p.Unlock() return newCount // 當有多個 return 分支時,很容易遺忘 unlock “` “`go p.Lock() defer p.Unlock() if p.count < 10 { return p.count } p.count++ return p.count // 更可讀 “`

Defer 的開銷非常小,只有在您可以證明函數執行時間處於納秒級的程度時,才應避免這樣做。使用 defer 提升可讀性是值得的,因為使用它們的成本微不足道。尤其適用於那些不僅僅是簡單內存訪問的較大的方法,在這些方法中其他計算的資源消耗遠超過 defer

Channel 的 size 要麼是 1,要麼是無緩衝的

channel 通常 size 應為 1 或是無緩衝的。默認情況下,channel 是無緩衝的,其 size 為零。任何其他尺寸都必須經過嚴格的審查。考慮如何確定大小,是什麼阻止了 channel 在負載下被填滿並阻止寫入,以及發生這種情況時發生了什麼。

Bad Good
“`go // 應該足以滿足任何情況! c := make(chan int, 64) “` “`go // 大小:1 c := make(chan int, 1) // 或者 // 無緩衝 channel,大小為 0 c := make(chan int) “`

枚舉從 1 開始

在 Go 中引入枚舉的標準方法是聲明一個自定義類型和一個使用了 iota 的 const 組。由於變量的默認值為 0,因此通常應以非零值開頭枚舉。

Bad Good
“`go type Operation int const ( Add Operation = iota Subtract Multiply ) // Add=0, Subtract=1, Multiply=2 “` “`go type Operation int const ( Add Operation = iota + 1 Subtract Multiply ) // Add=1, Subtract=2, Multiply=3 “`

在某些情況下,使用零值是有意義的(枚舉從零開始),例如,當零值是理想的默認行為時。

type LogOutput int

const (
  LogToStdout LogOutput = iota
  LogToFile
  LogToRemote
)

// LogToStdout=0, LogToFile=1, LogToRemote=2

錯誤類型

Go 中有多種聲明錯誤(Error) 的選項:

  • 對於簡單靜態字符串的錯誤
  • 用於格式化的錯誤字符串
  • 實現 Error() 方法的自定義類型
  • 用 的 Wrapped errors

返回錯誤時,請考慮以下因素以確定最佳選擇:

  • 這是一個不需要額外信息的簡單錯誤嗎?如果是這樣, 足夠了。
  • 客戶需要檢測並處理此錯誤嗎?如果是這樣,則應使用自定義類型並實現該 Error() 方法。
  • 您是否正在傳播下游函數返回的錯誤?如果是這樣,請查看本文後面有關錯誤包裝 部分的內容。
  • 否則 就可以了。

如果客戶端需要檢測錯誤,並且您已使用創建了一個簡單的錯誤 ,請使用一個錯誤變量。

Bad Good
“`go // package foo func Open() error { return errors.New(“could not open”) } // package bar func use() { if err := foo.Open(); err != nil { if err.Error() == “could not open” { // handle } else { panic(“unknown error”) } } } “` “`go // package foo var ErrCouldNotOpen = errors.New(“could not open”) func Open() error { return ErrCouldNotOpen } // package bar if err := foo.Open(); err != nil { if err == foo.ErrCouldNotOpen { // handle } else { panic(“unknown error”) } } “`

如果您有可能需要客戶端檢測的錯誤,並且想向其中添加更多信息(例如,它不是靜態字符串),則應使用自定義類型。

Bad Good
“`go func open(file string) error { return fmt.Errorf(“file %q not found”, file) } func use() { if err := open(); err != nil { if strings.Contains(err.Error(), “not found”) { // handle } else { panic(“unknown error”) } } } “` “`go type errNotFound struct { file string } func (e errNotFound) Error() string { return fmt.Sprintf(“file %q not found”, e.file) } func open(file string) error { return errNotFound{file: file} } func use() { if err := open(); err != nil { if _, ok := err.(errNotFound); ok { // handle } else { panic(“unknown error”) } } } “`

直接導出自定義錯誤類型時要小心,因為它們已成為程序包公共 API 的一部分。最好公開匹配器功能以檢查錯誤。

// package foo

type errNotFound struct {
  file string
}

func (e errNotFound) Error() string {
  return fmt.Sprintf("file %q not found", e.file)
}

func IsNotFoundError(err error) bool {
  _, ok := err.(errNotFound)
  return ok
}

func Open(file string) error {
  return errNotFound{file: file}
}

// package bar

if err := foo.Open("foo"); err != nil {
  if foo.IsNotFoundError(err) {
    // handle
  } else {
    panic("unknown error")
  }
}

錯誤包裝 (Error Wrapping)

一個(函數/方法)調用失敗時,有三種主要的錯誤傳播方式:

  • 如果沒有要添加的其他上下文,並且您想要維護原始錯誤類型,則返回原始錯誤。
  • 添加上下文,使用 以便錯誤消息提供更多上下文 , 可用於提取原始錯誤。
    Use fmt.Errorf if the callers do not need to detect or handle that specific error case.

  • 如果調用者不需要檢測或處理的特定錯誤情況,使用 。

建議在可能的地方添加上下文,以使您獲得諸如“調用服務 foo:連接被拒絕”之類的更有用的錯誤,而不是諸如“連接被拒絕”之類的模糊錯誤。

在將上下文添加到返回的錯誤時,請避免使用“failed to”之類的短語來保持上下文簡潔,這些短語會陳述明顯的內容,並隨着錯誤在堆棧中的滲透而逐漸堆積:

Bad Good
“`go s, err := store.New() if err != nil { return fmt.Errorf( “failed to create new store: %s”, err) } “` “`go s, err := store.New() if err != nil { return fmt.Errorf( “new store: %s”, err) } “`
“` failed to x: failed to y: failed to create new store: the error “` “` x: y: new store: the error “`

但是,一旦將錯誤發送到另一個系統,就應該明確消息是錯誤消息(例如使用err標記,或在日誌中以”Failed”為前綴)。

另請參見 . 不要只是檢查錯誤,要優雅地處理錯誤

處理類型斷言失敗

的單個返回值形式針對不正確的類型將產生 panic。因此,請始終使用“comma ok”的慣用法。

Bad Good
“`go t := i.(string) “` “`go t, ok := i.(string) if !ok { // 優雅地處理錯誤 } “`

不要 panic

在生產環境中運行的代碼必須避免出現 panic。panic 是 級聯失敗的主要根源 。如果發生錯誤,該函數必須返回錯誤,並允許調用方決定如何處理它。

Bad Good
“`go func foo(bar string) { if len(bar) == 0 { panic(“bar must not be empty”) } // … } func main() { if len(os.Args) != 2 { fmt.Println(“USAGE: foo “) os.Exit(1) } foo(os.Args[1]) } “` “`go func foo(bar string) error { if len(bar) == 0 { return errors.New(“bar must not be empty”) } // … return nil } func main() { if len(os.Args) != 2 { fmt.Println(“USAGE: foo “) os.Exit(1) } if err := foo(os.Args[1]); err != nil { panic(err) } } “`

panic/recover 不是錯誤處理策略。僅當發生不可恢復的事情(例如:nil 引用)時,程序才必須 panic。程序初始化是一個例外:程序啟動時應使程序中止的不良情況可能會引起 panic。

var _statusTemplate = template.Must(template.New("name").Parse("_statusHTML"))

即使在測試代碼中,也優先使用t.Fatal或者t.FailNow而不是 panic 來確保失敗被標記。

Bad Good
“`go // func TestFoo(t *testing.T) f, err := ioutil.TempFile(“”, “test”) if err != nil { panic(“failed to set up test”) } “` “`go // func TestFoo(t *testing.T) f, err := ioutil.TempFile(“”, “test”) if err != nil { t.Fatal(“failed to set up test”) } “`

使用 go.uber.org/atomic

使用 包的原子操作對原始類型 (int32, int64等)進行操作,因為很容易忘記使用原子操作來讀取或修改變量。

通過隱藏基礎類型為這些操作增加了類型安全性。此外,它包括一個方便的atomic.Bool類型。

Bad Good
“`go type foo struct { running int32 // atomic } func (f* foo) start() { if atomic.SwapInt32(&f.running, 1) == 1 { // already running… return } // start the Foo } func (f *foo) isRunning() bool { return f.running == 1 // race! } “` “`go type foo struct { running atomic.Bool } func (f *foo) start() { if f.running.Swap(true) { // already running… return } // start the Foo } func (f *foo) isRunning() bool { return f.running.Load() } “`

性能

性能方面的特定準則只適用於高頻場景。

優先使用 strconv 而不是 fmt

將原語轉換為字符串或從字符串轉換時,strconv速度比fmt快。

Bad Good
“`go for i := 0; i < b.N; i++ { s := fmt.Sprint(rand.Int()) } “` “`go for i := 0; i < b.N; i++ { s := strconv.Itoa(rand.Int()) } “`
“` BenchmarkFmtSprint-4 143 ns/op 2 allocs/op “` “` BenchmarkStrconv-4 64.2 ns/op 1 allocs/op “`

避免字符串到字節的轉換

不要反覆從固定字符串創建字節 slice。相反,請執行一次轉換並捕獲結果。

Bad Good
“`go for i := 0; i < b.N; i++ { w.Write([]byte(“Hello world”)) } “` “`go data := []byte(“Hello world”) for i := 0; i < b.N; i++ { w.Write(data) } “`
“` BenchmarkBad-4 50000000 22.2 ns/op “` “` BenchmarkGood-4 500000000 3.25 ns/op “`

盡量初始化時指定 Map 容量

在盡可能的情況下,在使用 make() 初始化的時候提供容量信息

make(map[T1]T2, hint)

make() 提供容量信息(hint)嘗試在初始化時調整 map 大小,
這減少了在將元素添加到 map 時增長和分配的開銷。
注意,map 不能保證分配 hint 個容量。因此,即使提供了容量,添加元素仍然可以進行分配。

Bad Good
“`go m := make(map[string]os.FileInfo) files, _ := ioutil.ReadDir(“./files”) for _, f := range files { m[f.Name()] = f } “` “`go files, _ := ioutil.ReadDir(“./files”) m := make(map[string]os.FileInfo, len(files)) for _, f := range files { m[f.Name()] = f } “`
`m` 是在沒有大小提示的情況下創建的; 在運行時可能會有更多分配。 `m` 是有大小提示創建的;在運行時可能會有更少的分配。

規範

一致性

本文中概述的一些標準都是客觀性的評估,是根據場景、上下文、或者主觀性的判斷;

但是最重要的是,保持一致.

一致性的代碼更容易維護、是更合理的、需要更少的學習成本、並且隨着新的約定出現或者出現錯誤后更容易遷移、更新、修復 bug

相反,一個單一的代碼庫會導致維護成本開銷、不確定性和認知偏差。所有這些都會直接導致速度降低、
代碼審查痛苦、而且增加 bug 數量

將這些標準應用於代碼庫時,建議在 package(或更大)級別進行更改,子包級別的應用程序通過將多個樣式引入到同一代碼中,違反了上述關注點。

相似的聲明放在一組

Go 語言支持將相似的聲明放在一個組內。

Bad Good
“`go import “a” import “b” “` “`go import ( “a” “b” ) “`

這同樣適用於常量、變量和類型聲明:

Bad Good
“`go const a = 1 const b = 2 var a = 1 var b = 2 type Area float64 type Volume float64 “` “`go const ( a = 1 b = 2 ) var ( a = 1 b = 2 ) type ( Area float64 Volume float64 ) “`

僅將相關的聲明放在一組。不要將不相關的聲明放在一組。

Bad Good
“`go type Operation int const ( Add Operation = iota + 1 Subtract Multiply ENV_VAR = “MY_ENV” ) “` “`go type Operation int const ( Add Operation = iota + 1 Subtract Multiply ) const ENV_VAR = “MY_ENV” “`

分組使用的位置沒有限制,例如:你可以在函數內部使用它們:

Bad Good
“`go func f() string { var red = color.New(0xff0000) var green = color.New(0x00ff00) var blue = color.New(0x0000ff) … } “` “`go func f() string { var ( red = color.New(0xff0000) green = color.New(0x00ff00) blue = color.New(0x0000ff) ) … } “`

import 分組

導入應該分為兩組:

  • 標準庫
  • 其他庫

默認情況下,這是 goimports 應用的分組。

Bad Good
“`go import ( “fmt” “os” “go.uber.org/atomic” “golang.org/x/sync/errgroup” ) “` “`go import ( “fmt” “os” “go.uber.org/atomic” “golang.org/x/sync/errgroup” ) “`

包名

當命名包時,請按下面規則選擇一個名稱:

  • 全部小寫。沒有大寫或下劃線。
  • 大多數使用命名導入的情況下,不需要重命名。
  • 簡短而簡潔。請記住,在每個使用的地方都完整標識了該名稱。
  • 不用複數。例如net/url,而不是net/urls
  • 不要用“common”,“util”,“shared”或“lib”。這些是不好的,信息量不足的名稱。

另請參閱 和 .

函數名

我們遵循 Go 社區關於使用 的約定。有一個例外,為了對相關的測試用例進行分組,函數名可能包含下劃線,如:TestMyFunction_WhatIsBeingTested.

導入別名

如果程序包名稱與導入路徑的最後一個元素不匹配,則必須使用導入別名。

import (
  "net/http"

  client "example.com/client-go"
  trace "example.com/trace/v2"
)

在所有其他情況下,除非導入之間有直接衝突,否則應避免導入別名。

Bad Good
“`go import ( “fmt” “os” nettrace “golang.net/x/trace” ) “` “`go import ( “fmt” “os” “runtime/trace” nettrace “golang.net/x/trace” ) “`

函數分組與順序

  • 函數應按粗略的調用順序排序。
  • 同一文件中的函數應按接收者分組。

因此,導出的函數應先出現在文件中,放在struct, const, var定義的後面。

在定義類型之後,但在接收者的其餘方法之前,可能會出現一個 newXYZ()/NewXYZ()

由於函數是按接收者分組的,因此普通工具函數應在文件末尾出現。

Bad Good
“`go func (s *something) Cost() { return calcCost(s.weights) } type something struct{ … } func calcCost(n []int) int {…} func (s *something) Stop() {…} func newSomething() *something { return &something{} } “` “`go type something struct{ … } func newSomething() *something { return &something{} } func (s *something) Cost() { return calcCost(s.weights) } func (s *something) Stop() {…} func calcCost(n []int) int {…} “`

減少嵌套

代碼應通過盡可能先處理錯誤情況/特殊情況並儘早返回或繼續循環來減少嵌套。減少嵌套多個級別的代碼的代碼量。

Bad Good
“`go for _, v := range data { if v.F1 == 1 { v = process(v) if err := v.Call(); err == nil { v.Send() } else { return err } } else { log.Printf(“Invalid v: %v”, v) } } “` “`go for _, v := range data { if v.F1 != 1 { log.Printf(“Invalid v: %v”, v) continue } v = process(v) if err := v.Call(); err != nil { return err } v.Send() } “`

不必要的 else

如果在 if 的兩個分支中都設置了變量,則可以將其替換為單個 if。

Bad Good
“`go var a int if b { a = 100 } else { a = 10 } “` “`go a := 10 if b { a = 100 } “`

頂層變量聲明

在頂層,使用標準var關鍵字。請勿指定類型,除非它與表達式的類型不同。

Bad Good
“`go var _s string = F() func F() string { return “A” } “` “`go var _s = F() // 由於 F 已經明確了返回一個字符串類型,因此我們沒有必要顯式指定_s 的類型 // 還是那種類型 func F() string { return “A” } “`

如果表達式的類型與所需的類型不完全匹配,請指定類型。

type myError struct{}

func (myError) Error() string { return "error" }

func F() myError { return myError{} }

var _e error = F()
// F 返回一個 myError 類型的實例,但是我們要 error 類型

對於未導出的頂層常量和變量,使用_作為前綴

在未導出的頂級varsconsts, 前面加上前綴_,以使它們在使用時明確表示它們是全局符號。

例外:未導出的錯誤值,應以err開頭。

基本依據:頂級變量和常量具有包範圍作用域。使用通用名稱可能很容易在其他文件中意外使用錯誤的值。

Bad Good
“`go // foo.go const ( defaultPort = 8080 defaultUser = “user” ) // bar.go func Bar() { defaultPort := 9090 … fmt.Println(“Default port”, defaultPort) // We will not see a compile error if the first line of // Bar() is deleted. } “` “`go // foo.go const ( _defaultPort = 8080 _defaultUser = “user” ) “`

結構體中的嵌入

嵌入式類型(例如 mutex)應位於結構體內的字段列表的頂部,並且必須有一個空行將嵌入式字段與常規字段分隔開。

Bad Good
“`go type Client struct { version int http.Client } “` “`go type Client struct { http.Client version int } “`

使用字段名初始化結構體

初始化結構體時,幾乎始終應該指定字段名稱。現在由 強制執行。

Bad Good
“`go k := User{“John”, “Doe”, true} “` “`go k := User{ FirstName: “John”, LastName: “Doe”, Admin: true, } “`

例外:如果有 3 個或更少的字段,則可以在測試表中省略字段名稱。

tests := []struct{
  op Operation
  want string
}{
  {Add, "add"},
  {Subtract, "subtract"},
}

本地變量聲明

如果將變量明確設置為某個值,則應使用短變量聲明形式 (:=)。

Bad Good
“`go var s = “foo” “` “`go s := “foo” “`

但是,在某些情況下,var 使用關鍵字時默認值會更清晰。例如,聲明空切片。

Bad Good
“`go func f(list []int) { filtered := []int{} for _, v := range list { if v > 10 { filtered = append(filtered, v) } } } “` “`go func f(list []int) { var filtered []int for _, v := range list { if v > 10 { filtered = append(filtered, v) } } } “`

nil 是一個有效的 slice

nil 是一個有效的長度為 0 的 slice,這意味着,

  • 您不應明確返回長度為零的切片。應該返回nil 來代替。

    Bad Good
    “`go if x == “” { return []int{} } “` “`go if x == “” { return nil } “`
  • 要檢查切片是否為空,請始終使用len(s) == 0。而非 nil

    Bad Good
    “`go func isEmpty(s []string) bool { return s == nil } “` “`go func isEmpty(s []string) bool { return len(s) == 0 } “`
  • 零值切片(用var聲明的切片)可立即使用,無需調用make()創建。

    Bad Good
    “`go nums := []int{} // or, nums := make([]int) if add1 { nums = append(nums, 1) } if add2 { nums = append(nums, 2) } “` “`go var nums []int if add1 { nums = append(nums, 1) } if add2 { nums = append(nums, 2) } “`

小變量作用域

如果有可能,盡量縮小變量作用範圍。除非它與 的規則衝突。

Bad Good
“`go err := ioutil.WriteFile(name, data, 0644) if err != nil { return err } “` “`go if err := ioutil.WriteFile(name, data, 0644); err != nil { return err } “`

如果需要在 if 之外使用函數調用的結果,則不應嘗試縮小範圍。

Bad Good
“`go if data, err := ioutil.ReadFile(name); err == nil { err = cfg.Decode(data) if err != nil { return err } fmt.Println(cfg) return nil } else { return err } “` “`go data, err := ioutil.ReadFile(name) if err != nil { return err } if err := cfg.Decode(data); err != nil { return err } fmt.Println(cfg) return nil “`

避免參數語義不明確(Avoid Naked Parameters)

函數調用中的意義不明確的參數可能會損害可讀性。當參數名稱的含義不明顯時,請為參數添加 C 樣式註釋 (/* ... */)

Bad Good
“`go // func printInfo(name string, isLocal, done bool) printInfo(“foo”, true, true) “` “`go // func printInfo(name string, isLocal, done bool) printInfo(“foo”, true /* isLocal */, true /* done */) “`

對於上面的示例代碼,還有一種更好的處理方式是將上面的 bool 類型換成自定義類型。將來,該參數可以支持不僅僅局限於兩個狀態(true/false)。

type Region int

const (
  UnknownRegion Region = iota
  Local
)

type Status int

const (
  StatusReady = iota + 1
  StatusDone
  // Maybe we will have a StatusInProgress in the future.
)

func printInfo(name string, region Region, status Status)

使用原始字符串字面值,避免轉義

Go 支持使用 ,也就是 ” ` ” 來表示原生字符串,在需要轉義的場景下,我們應該盡量使用這種方案來替換。

可以跨越多行並包含引號。使用這些字符串可以避免更難閱讀的手工轉義的字符串。

Bad Good
“`go wantError := “unknown name:\”test\”” “` “`go wantError := `unknown error:”test”` “`

初始化 Struct 引用

在初始化結構引用時,請使用&T{}代替new(T),以使其與結構體初始化一致。

Bad Good
“`go sval := T{Name: “foo”} // inconsistent sptr := new(T) sptr.Name = “bar” “` “`go sval := T{Name: “foo”} sptr := &T{Name: “bar”} “`

初始化 Maps

對於空 map 請使用 make(..) 初始化, 並且 map 是通過編程方式填充的。
這使得 map 初始化在表現上不同於聲明,並且它還可以方便地在 make 后添加大小提示。

Bad Good
“`go var ( // m1 讀寫安全; // m2 在寫入時會 panic m1 = map[T1]T2{} m2 map[T1]T2 ) “` “`go var ( // m1 讀寫安全; // m2 在寫入時會 panic m1 = make(map[T1]T2) m2 map[T1]T2 ) “`
聲明和初始化看起來非常相似的。 聲明和初始化看起來差別非常大。

在盡可能的情況下,請在初始化時提供 map 容量大小,詳細請看 。

另外,如果 map 包含固定的元素列表,則使用 map literals(map 初始化列表) 初始化映射。

Bad Good
“`go m := make(map[T1]T2, 3) m[k1] = v1 m[k2] = v2 m[k3] = v3 “` “`go m := map[T1]T2{ k1: v1, k2: v2, k3: v3, } “`

基本準則是:在初始化時使用 map 初始化列表 來添加一組固定的元素。否則使用 make (如果可以,請盡量指定 map 容量)。

字符串 string format

如果你為Printf-style 函數聲明格式字符串,請將格式化字符串放在外面,並將其設置為const常量。

這有助於go vet對格式字符串執行靜態分析。

Bad Good
“`go msg := “unexpected values %v, %v\n” fmt.Printf(msg, 1, 2) “` “`go const msg = “unexpected values %v, %v\n” fmt.Printf(msg, 1, 2) “`

命名 Printf 樣式的函數

聲明Printf-style 函數時,請確保go vet可以檢測到它並檢查格式字符串。

這意味着您應盡可能使用預定義的Printf-style 函數名稱。go vet將默認檢查這些。有關更多信息,請參見 。

如果不能使用預定義的名稱,請以 f 結束選擇的名稱:Wrapf,而不是Wrapgo vet可以要求檢查特定的 Printf 樣式名稱,但名稱必須以f結尾。

$ go vet -printfuncs=wrapf,statusf

另請參閱 .

編程模式

表驅動測試

當測試邏輯是重複的時候,通過 使用 table 驅動的方式編寫 case 代碼看上去會更簡潔。

Bad Good
“`go // func TestSplitHostPort(t *testing.T) host, port, err := net.SplitHostPort(“192.0.2.0:8000”) require.NoError(t, err) assert.Equal(t, “192.0.2.0”, host) assert.Equal(t, “8000”, port) host, port, err = net.SplitHostPort(“192.0.2.0:http”) require.NoError(t, err) assert.Equal(t, “192.0.2.0”, host) assert.Equal(t, “http”, port) host, port, err = net.SplitHostPort(“:8000”) require.NoError(t, err) assert.Equal(t, “”, host) assert.Equal(t, “8000”, port) host, port, err = net.SplitHostPort(“1:8”) require.NoError(t, err) assert.Equal(t, “1”, host) assert.Equal(t, “8”, port) “` “`go // func TestSplitHostPort(t *testing.T) tests := []struct{ give string wantHost string wantPort string }{ { give: “192.0.2.0:8000”, wantHost: “192.0.2.0”, wantPort: “8000”, }, { give: “192.0.2.0:http”, wantHost: “192.0.2.0”, wantPort: “http”, }, { give: “:8000”, wantHost: “”, wantPort: “8000”, }, { give: “1:8”, wantHost: “1”, wantPort: “8”, }, } for _, tt := range tests { t.Run(tt.give, func(t *testing.T) { host, port, err := net.SplitHostPort(tt.give) require.NoError(t, err) assert.Equal(t, tt.wantHost, host) assert.Equal(t, tt.wantPort, port) }) } “`

很明顯,使用 test table 的方式在代碼邏輯擴展的時候,比如新增 test case,都會顯得更加的清晰。

我們遵循這樣的約定:將結構體切片稱為tests。 每個測試用例稱為tt。此外,我們鼓勵使用givewant前綴說明每個測試用例的輸入和輸出值。

tests := []struct{
  give     string
  wantHost string
  wantPort string
}{
  // ...
}

for _, tt := range tests {
  // ...
}

功能選項

功能選項是一種模式,您可以在其中聲明一個不透明 Option 類型,該類型在某些內部結構中記錄信息。您接受這些選項的可變編號,並根據內部結構上的選項記錄的全部信息採取行動。

將此模式用於您需要擴展的構造函數和其他公共 API 中的可選參數,尤其是在這些功能上已經具有三個或更多參數的情況下。

Bad Good
“`go // package db func Connect( addr string, timeout time.Duration, caching bool, ) (*Connection, error) { // … } // Timeout and caching must always be provided, // even if the user wants to use the default. db.Connect(addr, db.DefaultTimeout, db.DefaultCaching) db.Connect(addr, newTimeout, db.DefaultCaching) db.Connect(addr, db.DefaultTimeout, false /* caching */) db.Connect(addr, newTimeout, false /* caching */) “` “`go type options struct { timeout time.Duration caching bool } // Option overrides behavior of Connect. type Option interface { apply(*options) } type optionFunc func(*options) func (f optionFunc) apply(o *options) { f(o) } func WithTimeout(t time.Duration) Option { return optionFunc(func(o *options) { o.timeout = t }) } func WithCaching(cache bool) Option { return optionFunc(func(o *options) { o.caching = cache }) } // Connect creates a connection. func Connect( addr string, opts …Option, ) (*Connection, error) { options := options{ timeout: defaultTimeout, caching: defaultCaching, } for _, o := range opts { o.apply(&options) } // … } // Options must be provided only if needed. db.Connect(addr) db.Connect(addr, db.WithTimeout(newTimeout)) db.Connect(addr, db.WithCaching(false)) db.Connect( addr, db.WithCaching(false), db.WithTimeout(newTimeout), ) “`

還可以參考下面資料:

本文由zshipu.com學習筆記或整理或轉載,如有侵權請聯繫,必改之。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

騰訊入股和諧汽車 鴻海間接掌理電池電動車業務

中國大陸和諧汽車公告,旗下的河南和諧公司將轉讓55%綠野汽車的股權給和諧富騰。和諧富騰為和諧汽車、騰訊集團、鴻海集團的合資公司,鴻海等同間接投資綠野汽車,並握有鋰電池電動車相關業務。

綠野汽車為和諧汽車旗下的電動車品牌,由和諧汽車另一子公司河南和諧持有大部分股權。本次轉讓55%股權,和諧富騰將付2.64億港元給河南和諧。轉讓完成後,和諧富騰將成為綠野汽車控股股東,而和諧汽車則透過河南和諧持有綠野汽車32.57% 的股權。

和諧富騰由騰訊集團旗下深圳騰訊持有29.4%股權、河南和諧持有39.2%股權、鴻海集團旗下鴻富錦精密電子持有29.4%、其餘2%由管理公司持有。該公司主要業務為新能源與智慧電動車發展,以及相關的互聯網投資。

綠野汽車以開發鋰電池動力的高速電動汽車為主要方向。和諧汽車表示,將延攬更多有經驗的人才與投資者來發展綠野汽車的業務。

鴻海集團藉著這次的股權轉讓,對和諧汽車持股增加,已是第二大股東。其入股目標主要放眼於中國大陸的電動車市場發展。經過和諧富騰本次入股綠野汽車,鴻海集團將持有鋰電池電動車相關的發展業務。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

福特砸45億美元擴增電動車產線

美商福特汽車(Ford)宣布將投資45億美元擴增電動車生產線,目標在五年內將旗下電動車產品的比例從目前的13%提高到40%左右,同時陸續推出共13款新的電動車與油電混和車。

隨著汽車排放標準愈趨嚴格,福特汽車認為電動車領域的吸引力將比過去更高,因此宣布擴增電動車產線。執行長Mark Fields 表示,在即將推出的13款新車中,也包括有快速充電功能的Focus Electric車款。

近來油價低廉,美國電動車、油電混和車的銷量因而受到壓抑,但福特認為車商仍必須讓消費者了解電動車款的優點,且認為電動車的投資未來將能與一般汽油車擁有差不多的獲益。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

2016年新能源汽車補貼標準出爐

根據財政部此前發佈的《關於2016-2020年新能源汽車推廣應用財政支持政策的通知》,2016年乘用車以純電動續航行駛里程(R)為標準,具體補貼如下。

1、純電動乘用車100km≤R<150km每車2.5萬、150km≤R<250km每車4.5萬、R≥250km每車5.5萬元。

2、插電式混合動力乘用車(含增程式)R≥50km每車補貼3萬元;

相比2013年-2015年新能源車補貼政策,純電動乘用車的續駛里程由大於等於80km提升至100km,補貼減少0.5萬元;插電式混合動力乘用車(含增程式),補貼減少0.5萬元。

此外,純電動、插電式混合動力客車,電動、插電式混合動力(含增程式)等專用車、貨車也在補貼範圍之中.

據瞭解,2017-2020年除燃料電池汽車外其他車型補助標準適當退坡,其中:2017-2018年補助標準在2016年基礎上下降20%,2019-2020年補助標準在2016年基礎上下降40%。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

Gogoro進軍桃竹 桃園補助全台最高

台灣電動機車Gogoro正式從台北「南進」桃園、新竹。本月19日,第一家Gogoro桃園門市開幕;同時,Gogoro在新竹也與超商業者萊爾富合作,成立第一個新竹GoStation電池交換站。

桃園市長:電動車補助名額無上限

根據EnergyTrend 的了解,桃園市是全台對電動車、充電樁等相關設施補助最積極的都市。本次Gogoro率先於台北以外地區成立門市,桃園市長鄭文燦也趁機宣布桃園市民購買電動二輪車的補助名額無上限,希望能強化市民採購電動車的意願,降低交通空氣汙染,讓桃園市更加環保。

鄭文燦受邀參加Gogoro桃園門市開幕活動,表示桃園目前有23,00輛電動機車,是全台電動機車最多的城市。凡是桃園市民新購買電動機車,就享有新台幣16,000元的補助,由二行程機車汰換為電動機車者享22,000補助,更換電池則享4,000元補助。鄭文燦表示,桃園市未來將擴大補貼政策,希望能帶動電動車需求成長,達到每年新增一萬輛的目標。

除了購車補貼之外,桃園市政府也正在制定相關法規,預計透過〈桃園市發展低碳綠色城市自治條例〉進行制度化發展。此外,桃園市也在停車場、加油站、公有設施等場所建設五百餘座充電站,透過增設充電點的方式來提升電動機車的方便性。

Gogoro將與桃園市政府配合,在市政府架設充電區與GoStation電池交換站。

新竹:Hi-Life新竹竹亮店站啟用

Gogoro在新竹的服務先以設置GoStation電池交換站開始,選擇與萊爾富合作,於新竹竹亮店門市成立第一座電池交換站,且預計在12月24日陸續啟用竹北竹文站、竹北竹發站、竹北北鮮站等與超商結合的交換站,陸續拓展站點。

Gogoro宣布,目前已準備上路的新竹電池交換站數量已超過10個,桃、竹地區今年年底前的GoStation數量將超過35座。Gogoro也在新竹成立了銷售門市,提供銷售、體驗、維修、換電服務。門市開幕期間也將限時推出購車好禮活動,

(照片來源:Gogoro Taiwan臉書粉絲團)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

澳洲野火關鍵課題:找回原民治火技術、反思進逼森林的都市擴張

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

比亞迪或放大招:新能源車3年內可回購

1月6日下午,網友@霏非凡在其個人微博上曝光了一張手機截圖,截圖是比亞迪官方向深圳地區的經銷商發送的一份通知,標題顯示為“關於發佈比亞迪新能源汽車保值回購政策的通知”。

通知內容顯示:新車購買發票日期滿1年之日起30天內可享受M*85折回購,發票日期滿2年之日起30天內可享受M*75折回購,而發票日期滿3年之日起30天內可享受M*65折回購。其中,M的定義為官方指導價減去購車補貼金額(包含國家+地方補貼)之後的價格,也就是車主的購買比亞迪新能源車實際支付價格。

目前,新車回購整車政策貌似只針對于深圳經銷商,比亞迪官方也並未正式向外界公佈這一消息,因此新能源車回購政策否會在全國範圍內推行還有待進一步考證。

文章來源:電動邦

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益