保值率有啥用?看了才知道這些十幾萬的國產SUV這麼值錢

無論是從消費者口中還是市場銷量,無一不證明傳祺GS4擁有過人的產品實力。首先是原創度極高的外觀設計,年輕運動的造型風格拉攏了多少追求個性的年輕人,在整個自主SUV市場可是非常搶眼。與此同時,傳祺GS4的空間表現、動力總成,均在同級中有不錯的產品賣點,加上實惠的購車、養車成本。

二手車市場中流傳着這麼一句話:新車落地打八折。不管你是豪車還是家用車,只要是用過一段時間,先在新車的售價基礎上砍掉20%再談。因此,很多精打細算的消費者也會在準備購車前,未雨綢繆,盡量多方打聽某款車型的保值率,以便未來出手時能預測虧損區間。但是,保值率是什麼,你真的了解嗎?



長安CS75

新車價:9.28-15.88萬

保值率:57.70%

長安作為一家自主品牌的老大哥,旗下的CS系列均有口皆碑。其中,最受好評的還是長安CS75,沉穩大氣的外觀形象,雖然看起來中庸點,但卻非常符合國人骨子里對於傳統SUV的想象,寬敞又舒適的大空間也為長安CS75贏得一片掌聲。

除此之外,同級別非常有誠意的配置,成熟可靠的強勁動力,綜合起來真的不比合資SUV差。一句話下來,但凡SUV應該具備的特質,長安CS75都一個不漏地呈現給消費者,這也難怪長安CS75在二手車市場依然那麼搶手,保值率居高不下自然是常態。更何況,近期長安CS75 1.5T車型的上市,無疑進一步降低了購車門檻和成本。



傳祺GS4

新車價:9.98-15.38萬元

保值率:58.90%

上市不足兩年的傳祺GS4,一舉成為當今最受關注度的自主SUV之一。無論是從消費者口中還是市場銷量,無一不證明傳祺GS4擁有過人的產品實力。首先是原創度極高的外觀設計,年輕運動的造型風格拉攏了多少追求個性的年輕人,在整個自主SUV市場可是非常搶眼。

與此同時,傳祺GS4的空間表現、動力總成,均在同級中有不錯的產品賣點,加上實惠的購車、養車成本。這樣既有顏值又有實力,性價比還不低的傳祺GS4,又豈有賣不好的道理。另外,步入今年以來,傳祺GS4的市場表現愈加穩定,月銷兩三萬輛穩居SUV市場亞軍,以上有利因素都造就了傳祺GS4較高的保值率。值得一提的是,隨着傳祺GS4 6AT變速箱車型的上市,相信消費者對於其購買熱情只會有增無減。



哈弗H6

新車價:8.88-16.28萬

保值率:56.40%

提到自主SUV的保值率,是無法如何是避不開神車哈弗H6的。事實上,關於哈弗H6保值率高的原因也不難理解,只要了解它一個月賣出去的天量,再算一算哈弗H6在神州大地的保有量規模,你會發現其它的國產車簡直是渣渣的存在。

當然,哈弗H6的熱銷不是憑空而來,其一是抓對了早期自主SUV市場的空白期,可以算是第一個吃大螃蟹的自主SUV,為哈弗H6今時今日的頭把交椅奠定了良好的群眾基礎。其二是哈弗H6基本上完全針對國人的審美點出發打造,無論外觀還是空間,都讓人非常容易接受。此外,哈弗H6多到數不清的車型(紅藍標,運動升級版…),一定程度上幫助了哈弗H6滿足不同需求的消費者,再加上終端方面的讓利促銷。哈哈哈,如此才會延續哈弗H6越賣越好的節奏,哪怕是在二手車市場也是一車難求。

總結

以上推薦的幾款國產SUV,只是在保值率較高中比較有代表性的幾位。事實上,隨着國產SUV整體品質的提升,以及市場保有量的不斷擴大,許多有顏值有實力的國產SUV也越來越值錢,告別了以往二市車市場無人問津的尷尬。相比之下,國產轎車仍需加把勁啊。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

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

※教你寫出一流的銷售文案?

※超省錢租車方案

※回頭車貨運收費標準

同樣是傳祺的SUV,為啥大家都愛GS4不買GS5?真是GS5不好嗎?

那就是如今傳祺非常紅火的GS4車型了,它較低的起步價更加的親民。而時尚的外觀與內飾設計配合一樣出色的底盤,因此它熱銷就不難想象了。就現在來看,傳祺GS5真的不值得購買么。今天就來好好對比下,看看它們哪款比較出色。

國產SUV在最近這幾年發力非常猛,大有超過日韓SUV的氣勢。究其原因是自主品牌經過多年的技術積累,同時堅持正向研發配合大量的資金投入的基礎下的成果。而且如今的自主廠商也漸漸的意識到只有原創的設計,符合大眾的審美的車型才能在激烈競爭的市場上生存下來。

回顧前幾年的SUV市場,當然合資品牌還沒有很多SUV車型推出。因此當然也有一些自主品牌看中了合資品牌沒有佔領了15萬這個區間的緊湊SUV市場,於是推出一些實力還算比較出色的SUV車型來提升自家的品牌形象,其中傳祺GS5 Super就是最突出的例子。它的外觀原創度很高,整體的底盤調校與做工都非常出色,無奈是當時由於定價的偏高與消費者對自主SUV的認可還沒有現在這麼深,於是它的市場表現一直不算很出色。

雖然GS5 Super有點出師不利,但它前期推出市場還是有不少的消費者購買的,它出色的做工與良好的底盤響應都使得傳祺在市場上有了不錯的口碑,於是就有了後來的事情了。那就是如今傳祺非常紅火的GS4車型了,它較低的起步價更加的親民。而時尚的外觀與內飾設計配合一樣出色的底盤,因此它熱銷就不難想象了。就現在來看,傳祺GS5真的不值得購買么?今天就來好好對比下,看看它們哪款比較出色?

綜上所述,目前的GS5 Super相比GS4除了動力有一定的優勢之外,它的價格仍然是一大硬傷,當然如今消費者對傳祺的認可已經很不錯了,就像其最新推出的GS8一樣,只要品質足夠的出色,熱銷真的不是問題。

那麼未來GS5 Super要怎麼才能重新煥發青春呢?在看來,如今最亟待改變的就是換裝全新的家族式面孔,與傳祺的其他車型有良好的延續,同時內飾的造型與配置都要相應的提升,這樣只要保持之前的行駛質感的話再把價格降低一些。這樣的話,相信GS5 Super要熱賣真的不成問題。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

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

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

傳奇新生 換裝1.5L發動機的新捷達有什麼變化

電影結束后,一汽-大眾汽車有限公司董事、總經理張丕傑上前發表感言致辭,喚醒“國民情捷”,引發情感共鳴宣布《平凡成就偉大》這部舞台劇正式演出,男主角為了尋找父親以前賣了的老捷達,從而找上尋車的道路。外觀更時尚年輕化外觀方面,我們可以看到像邁騰、朗逸那樣大眾最新的橫貫式前臉設計語言,從正前臉看去,X造型的設計元素使車頭帶來很強的視覺衝擊,彰顯了新捷達的力量和運動感。

問起老一輩人最熟悉的車型,他們肯定會異口同聲的說老三樣:捷達、富康、桑塔納,也許連他們自己都難以想象,捷達已經和國人的緣分已經走過了25個年頭,捷達承載的不只是一代人甚至是兩代人的美好回憶,卓越的品質使其締造了一個又一個傳奇。

12月7日晚,備受關注的新捷達在廣州亞運城綜合體育館正式上市,提供了1.4L、1.5L、1.4T三種動力共9款車型,售價區間在7.99-13.49萬元之間。

從場外觀看,可見捷達的發布會充滿着時尚的元素,藍色主題的燈光,音樂節般的場景布局,是否意味着這次新捷達更時尚年輕化的設計路線呢?

走進發布會的場館內,彷彿走進了一個汽車的博物館,每一輛車子都是時間的見證者,25年來所推出的所有捷達車型湧現眼前。

一部簡述捷達的國民情節大電影拉開了發布會的帷幕,描述捷達在中國汽車市場的25年傳奇經歷,多項技術的創新、時代的發展、團隊的奮鬥都歷歷在目。

電影結束后,一汽-大眾汽車有限公司董事、總經理張丕傑上前發表感言致辭,喚醒“國民情捷”,引發情感共鳴宣布《平凡成就偉大》這部舞台劇正式演出,男主角為了尋找父親以前賣了的老捷達,從而找上尋車的道路。

外觀

更時尚年輕化

外觀方面,我們可以看到像邁騰、朗逸那樣大眾最新的橫貫式前臉設計語言,從正前臉看去,X造型的設計元素使車頭帶來很強的視覺衝擊,彰顯了新捷達的力量和運動感。

側面的簡潔流暢額腰線從前翼子板一直延伸至車尾,使整個車身顯得更加修長,搭配硬朗有力的曲面輪廓,給人很緊緻飽滿的感覺,全新造型的輪轂,更突顯了整車的運動氛圍,尾部的設計頗有種小寶來的味道。

內飾

全面升級

沿用了大眾最新的內飾設計風格,全新設計的組合儀錶盤和平底式方向盤,金屬質感的裝飾板和烤漆面板的合理搭配,營造了很好的質感,更讓車內充滿時尚運動的氣息,配置方面根據車型不同,配備有自動空調、感應雨刷、自動頭燈、座椅加熱、定速巡航、胎壓監測等非常豐富的配置。

動力

全新的動力總成

全新的EA211系列1.5L自然吸氣發動機取代了之前的1.6L發動機,最大功率110馬力,最大扭矩150牛米,擁有雙VVT正時調節系統,持續可調式機油泵等先進技術,降低油耗的同時,排放和噪音也改善了不少,與之匹配的是5擋手動或者6擋自動變速器,而1.4L和1.4T發動機得以保留。

總結:本次上的新捷達外觀上有了較大的變化,更家族化的外觀使大眾的車型更加統一了,更時尚年輕的外觀造型適應的人群也更廣了,內飾的配置、造型、用料都有很大的調節和提升,同時新增的1.5L發動機無論是動力和燃油經濟性都有所提升,可以說捷達的競爭力提升了很多。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

把寶馬開到0.9升油耗!我是如何做到的?

而想全程用電機行駛,就需要切換到Max eDrive模式。電量不足的情況下,你可以選擇Save Battery模式來存電。不得不說,在純電模式下,X1 25Le表現得非常安靜,加上因為完全靠電機驅動,峰值扭矩能全數輸出,所以起步階段非常迅速,完全不用擔心起步遲緩的問題。

寶馬長期以來都是以直六+后驅的形象示人,但自從推出了UKL前置前驅平台之後,就出現了一些批評聲音,部分車迷表示接受不了。而寶馬的全新X1正是這個平台的產物,但不同的是,國產X1除了加長軸距外,還推出了以後驅為主的插電式混合動力車型。

在行駛的過程中,X1 25Le會根據不同的eDrive模式切換不同的驅動形式。在Auto eDrive模式中,ECU會自行在純電、油電混合和純發動機驅動三個模式中自動切換。而想全程用電機行駛,就需要切換到Max eDrive模式。電量不足的情況下,你可以選擇Save Battery模式來存電。

而在自動模式下,只要轉速超過2000轉,發動機就會自動介入,驅動前輪行駛。但要說有什麼不同,還真的沒必要去感受,因為整套系統運行得非常順暢。

另外X1 25Le所使用的電池凈容量為10.7kWh,理論巡航里程是60km左右,但極限情況下可達80km。通過220V的電源接口充電,充滿電只需3.7小時。

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

【其他文章推薦】

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

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

Java編程技術之淺析JVM內存

JVM

JVM->Java Virtual Machine:Java虛擬機,是一種用於計算設備的規範,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。

基本認知:

  • 1.JVM是用於運行Java代碼的假象計算機,主要有一套字節碼指令集,一組寄存器,一個棧,一個垃圾回收,堆 和 一個存儲方法域。
  • 2.JVM運行在操作系統之上,與硬件沒有直接的交互。

Java程序執行過程:

  • 1.編譯->源文件由編譯器編譯成字節碼[ByteCode]

Java 源文件—->編譯器—->字節碼文件

  • 2.運行->字節碼由java虛擬機解釋運行

字節碼文件—->JVM—->機器碼

Java類的加載步驟:

  • 1.加載->主要是完成3個階段的提交:

通過類的全限定名來獲取定義類的二進制字節流
將字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構
在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口。

  • 2.驗證->四個階段的檢驗動作:

文件格式驗證
元數據驗證
字節碼驗證
符號引用驗證

  • 3.準備->為類變量(static)分配內存並設置類變量的初始值。
  • 4.解析->將常量池內的符號引用轉為直接的引用
  • 5.初始化->按照static塊和static變量在文件中的出現順序,合併到 ()方法中。實例變量由 ()函數賦值。

JVM線程實體:

JVM線程->程序執行過程中的一個線程實體,JVM 允許一個應用併發執行多個線程。

從此,我們應該意識到,在Java中,當提到線程就應該是指JVM線程和Java線程。其中JVM線程指的是Hotspot JVM 後台運行的系統線程,而且Hotspot JVM 中的 Java 線程與原生操作系統線程有直接的映射關係。

️[注意事項]:
[1].當線程本地存儲、緩衝區分配、同步對象、棧、程序計數器等準備好以後,就會創建一個操作系統原生線程。
[2].Java 線程結束,原生線程隨之被回收。操作系統負責調度所有線程,並把它們分配到任何可用的 CPU 上。
[3].當原生線程初始化完畢,就會調用 Java 線程的 run() 方法。當線程結束時,會釋放原生線程和 Java 線程的所有資源

特別需要知道的是,Hotspot JVM 後台運行的系統線程主要是:

  • 虛擬機線程->VM thread:等待 JVM 到達安全點操作出現。這些操作必須要在獨立的線程里執行,因為當堆修改無法進行時,線程都需要 JVM 位於安全點。這些操作的類型有:stop-theworld垃圾回收、線程棧 dump、線程暫停、線程偏向鎖(biased locking)解除。
  • 周期性任務線程->負責定時器事件(也就是中斷),用來調度周期性操作的執行
  • GC線程->支持 JVM 中不同的垃圾回收活動
  • 編譯器線程->在運行時將字節碼動態編譯成本地平台相關的機器碼
  • 信號分發線程->程接收發送到 JVM 的信號並調用適當的 JVM 方法處理

JVM內存

版權聲明:本文為博主原創文章,遵循相關版權協議,如若轉載或者分享請附上原文出處鏈接和鏈接來源。

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

【其他文章推薦】

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

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

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

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

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

xlua中lua對象到c#對象的轉型

lua中的類型

基礎類型

#define LUA_TNIL		0
#define LUA_TBOOLEAN		1
#define LUA_TLIGHTUSERDATA	2
#define LUA_TNUMBER		3
#define LUA_TSTRING		4
#define LUA_TTABLE		5
#define LUA_TFUNCTION		6
#define LUA_TUSERDATA		7
#define LUA_TTHREAD		8

變體(或者說子類型)

/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* value)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/

/*
** LUA_TFUNCTION variants:
** 0 - Lua function
** 1 - light C function
** 2 - regular C function (closure)
*/

/* Variant tags for functions */
#define LUA_TLCL	(LUA_TFUNCTION | (0 << 4))  /* Lua closure */
#define LUA_TLCF	(LUA_TFUNCTION | (1 << 4))  /* light C function */
#define LUA_TCCL	(LUA_TFUNCTION | (2 << 4))  /* C closure */


/* Variant tags for strings */
#define LUA_TSHRSTR	(LUA_TSTRING | (0 << 4))  /* short strings */
#define LUA_TLNGSTR	(LUA_TSTRING | (1 << 4))  /* long strings */


/* Variant tags for numbers */
#define LUA_TNUMFLT	(LUA_TNUMBER | (0 << 4))  /* float numbers */
#define LUA_TNUMINT	(LUA_TNUMBER | (1 << 4))  /* integer numbers */


/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE	(1 << 6)

  lua中的對象都是用TValue來描述的,TValue中的tt_成員變量代表着這個TValue的類型。關於類型的具體定義,上面貼的代碼中的註釋中已經講的比較清楚了。
  一個lua對象的類型是由一個7位的bits描述的。比如一個整數,這個對象的類型就是0011000(24)表示這個對象是数字類型中的整形,是一個不可回收對象。

C#如何獲取lua對象

  和c語言和lua交互其實沒啥本質區別,就是通過lua提供的c函數操作lua棧,直接從棧中取就可以了。區別在於如何把取到的值轉換為c#認識的值。

如何在C#端描述這些類型

簡介

  lua的類型中boolean、string、number這幾個類型是clr所認識的類型,所以clr就可以直接把這些類型拿過來用。具體就是直接調用Lua提供的lua_tonumber之類的c接口。
  lightUserData、table、function、userData、thread是C#不認識的類,需要通過某種標識(lua自帶的reference系統)來表示。

boolean、string、number類

  這三個類上面已經說過了,直接用提供的接口轉就可以,下面寫幾個需要注意的點:

  1. string雖然也是一個引用類型,但是clr在拿到這個string的指針時,還需要將這個string的數據直接複製進clr中才算轉型結束(xlua也已經封裝好了,不用我們自己去複製)。
  2. 大部分類型轉型失敗的時候都不會報錯,而是會返回一個默認值。就拿將一個lua對象轉為int來說,最終是通過lua_tointegerx函數調用的,當lua對象不是number類型時,返回0:
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
  lua_Integer res;
  const TValue *o = index2addr(L, idx);
  int isnum = tointeger(o, &res);
  if (!isnum)
    res = 0;  /* call to 'tointeger' may change 'n' even if it fails */
  if (pisnum) *pisnum = isnum;
  return res;
}
  1. 當一個number類型是浮點數時,轉型整數不會進行取整操作,而是會直接返回0。因為lua默認對float轉int的操作模式LUA_FLOORN2I是0,代表碰見float轉int時返回0。
/*
** try to convert a value to an integer, rounding according to 'mode':
** mode == 0: accepts only integral values
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
  TValue v;
 again:
  if (ttisfloat(obj)) {
    lua_Number n = fltvalue(obj);
    lua_Number f = l_floor(n);
    if (n != f) {  /* not an integral value? */
      if (mode == 0) return 0;  /* fails if mode demands integral value */
      else if (mode > 1)  /* needs ceil? */
        f += 1;  /* convert floor to ceil (remember: n != f) */
    }
    return lua_numbertointeger(f, p);
  }
  else if (ttisinteger(obj)) {
    *p = ivalue(obj);
    return 1;
  }
  else if (cvt2num(obj) &&
            luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
    obj = &v;
    goto again;  /* convert result from 'luaO_str2num' to an integer */
  }
  return 0;  /* conversion failed */
}

userData

  userData主要是lua對c#對象的引用,這裏只簡單說一下。
  代表c#對象的userData主要分兩種。

  1. 把c#對象存在ObjectTranslator中,用下標作為引用(類似於lua中的reference)。
  2. 經過GC優化的結構體和枚舉,不存在ObjectTranslator中,而是把所有內容都打包到userdata中一起傳入lua中。比如一個Vector3,那麼xlua會把這個Vector3的x、y、z作為3個連續的float一起打包到userdata中。這樣就避免了c#層的裝箱、拆箱和gc操作。

對table與function的引用簡介

  這兩個類型都是通過lua的reference系統來讓c#持有對lua對象的引用。

lua reference系統

  c#就是通過這個系統來持有不認識的lua對象的。
  一共就兩個接口:

  1. luaL_ref:把棧頂元素加入一個lua的表中,並返回下標。
  2. luaL_unref:把一個下標所代表元素從表中刪除。

  這樣就可以用一個整數來讓lua外的環境持有這個lua對象。
具體可以看下官方說明lua References

luaBase類

  所有lua對象在c#中的基類,在初始化時通過luaL_ref生成lua對象的引用,在析構時通過luaL_unref移除引用。

對table的引用

LuaTable

  一般情況下table在C#中被包裝為LuaTable類,沒啥特別的,只是在LuaBase的基礎上增加了幾個常用的函數。比如Get、Set之類的,讓開發者可以避開一些不直觀的棧操作。

Array、List、Dictionary

  這幾個都差不多。都是把table中的key和value全部拿出來,組成Array或Dictionaray。

接口、其他類

  這兩種轉型是嘗試把這個table看作對應的接口或類。
  比如將一個table轉為IEnumberator就是把table轉為SystemCollectionsIEnumeratorBridge類(繼承了LuaBase、實現了IEnumerator的類,由Xlua生成),這個類實現了MoveNext和Reset。實現方法就是調用一下table中對應名稱的函數。

對function的引用

  lua函數在c#中有兩種表示:

LuaFunction

  LuaFunction和luaTable差不多,也是在LuaBase的基礎上增加了幾個常用函數,Call、Action之類的。

DelegateBridge

  為什麼已經有LuaFunction還要一個DelegateBridge類?
  因為我們在c#中拿到一個lua函數時,大多數時候是要作為一個委託來時用的。DelegateBridge就是用來化簡這個轉型操作的。
  DelegateBridge的功能就是在持有lua函數引用的同時,將這個函數包裝成各種各樣的委託,讓整個轉型過程對開發人員無感知。
  下面是一個不使用DelegateBridge,自己轉型的例子,比較繁瑣:

//將一個LuaFunction作為一個Action<int>使用
//其實LuaFunction.Cast就是干這個的,這裏只是用簡單的方式表達出來
public static Action<int> LuaFunctionToActionInt(XLua.LuaFunction luaFunction)
{
    //由於luaFunction已經提供了Call操作封裝了函數調用的各種棧操作,所以我們這裏只需要用一個Action<int>把這個操作包裝起來即可
    return (x) =>
    {
        luaFunction.Call(x);
    };
}

public static void Test()
{
    XLua.LuaEnv luaEnv = new XLua.LuaEnv();
    object[] rets = luaEnv.DoString("return function(x) CS.UnityEngine.Debug.LogError(\"print x: \"..x) end");
    var luaFunction = (XLua.LuaFunction)rets[0];
    Action<int> actionInt = LuaFunctionToActionInt(luaFunction);
    actionInt(10);
}

DelegateBridge重要成員

xlua在將lua函數轉型的時候做了什麼

Tips

  1. 通過ObjectTranslator.getDelegateUsingGeneric生成委託時,會對返回值和參數進行不為值類型的約束。因為值類型在il2cpp下會有jit異常。這也是為什麼我們發現有的委託類型不用註冊也可以使用,但是有的就不行。
  2. 在編輯器模式下,沒有進行代碼生成時,會通過Emit直接生成一個XLuaGenDelegateImplx類,內容和通過代碼生成后的DelegateBridge一樣,而不是全部通過反射來進行轉型。讓沒有進行代碼生成時的環境和真機環境更接近。
  3. DelegateBridge一般不會被直接引用,而是被bindto中的委託生成的閉包引用和被delegate_bridges作為弱引用持有。當一個DelegateBridge的bindto中的委託沒有被任何對象引用時,這個DelegateBridge就會在下次gc時被gc掉。

其他

  這裏主要寫了常用lua類型轉型的簡介和一些關鍵點。可能不夠全面和細節。
  如果有什麼錯誤或者問題可以在下面留言。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

golang連接達夢數據庫的一個坑

golang連接達夢數據庫的一個坑

有一次項目中用到了達夢數據庫,後端語言使用的golang,達夢官方並未適配專門的golang連接方式,正一籌莫展的時候發現達夢提供了odbc的連接,這樣可以使用類似mssqlodbc連接方式連接達夢數據庫。

使用的達夢數據庫版本為DM8

達夢數據庫開啟odbc連接

參考博客1、參考博客2

參照上面兩個博客內容配置odbc連接

golang代碼

一些參考文檔:

package main
import (
	"fmt"
	_ "github.com/alexbrainman/odbc"  // google's odbc driver
	"github.com/go-xorm/xorm"
	"xorm.io/core"
	"github.com/axgle/mahonia"
)

type Address struct {
    Addressid int64 `xorm:"addressid"`
    Address1 string `xorm:"address1"`
    Address2 string `xorm:"address2"`
    City string `xorm:"city"`
    Postalcode string `xorm:"postalcode"`
}

// 字符串解碼函數,處理中文亂碼
func ConvertToString(src string, srcCode string, tagCode string) string {
    srcCoder := mahonia.NewDecoder(srcCode)
    srcResult := srcCoder.ConvertString(src)
    tagCoder := mahonia.NewDecoder(tagCode)
    _, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
    result := string(cdata)
    return result
}

func main() {
	engine, err := xorm.NewEngine("odbc", "driver={DM8 ODBC DRIVER};server=127.0.0.1:5236;database=DM;uid=SYSDBA;pwd=password;charset=utf8")
	if err != nil {
		fmt.Println("new engine got error:", err)
		return
	}
	engine.ShowSQL(true)//控制台打印出生成的SQL語句;
	engine.Logger().SetLevel(core.LOG_DEBUG)
	if err := engine.Ping(); err != nil {
		fmt.Println("ping got error:", err)
		return
	}

	// 1) sql查詢
	results, err := engine.Query("select addressid, address1, address2, city, postalcode from person.address limit 5 offset 2")
	if err != nil {
		fmt.Println("查詢出錯:", err)
		return
	}
	for i, e := range results {
		fmt.Printf("%v\t", i)
		for k, v := range e {
			// 達夢數據庫中文默認為gbk
			fmt.Printf("%v=%v\t", k, ConvertToString(string(v), "gbk", "utf-8"))
		}
		fmt.Printf("\n")
	}
	fmt.Println("*******************************")
	// 2) 使用struct 映射結果
	engine.SetMapper(core.SameMapper{})
	var sliceOfAddress []Address
	err = engine.Table("person.address").Limit(5, 0).Find(&sliceOfAddress)
	if err != nil {
		fmt.Println("查詢出錯:", err)
		return
	}
	for i,e := range sliceOfAddress {
		e.Address1 = ConvertToString(e.Address1, "gbk", "utf-8")
		e.Address2 = ConvertToString(e.Address2, "gbk", "utf-8")
		e.City = ConvertToString(e.City, "gbk", "utf-8")
		fmt.Printf("%v=%v\n", i, e)
	}
}

1)解決 golang.org/x/ 下包下載不下來的問題

https://studygolang.com/articles/19051?fr=sidebar

https://studygolang.com/articles/24075?fr=sidebar

2)無效的表或視圖名[person.address](這個也是最坑的一點)

原因:我們使用的是odbc的方式連接達夢數據庫,實際上使用的是mssql的驅動,第一個1) SQL查詢結果是OK的,但是2) struct 查詢就會報錯:

[xorm] [info]  2020/06/08 16:52:40.183731 [SQL] SELECT TOP 5 "addressid", "address1", "address2", "city", "postalcode" FROM "person.address"
查詢出錯: SQLPrepare: {42S02} 第1 行附近出現錯誤:
無效的表或視圖名[person.address]

通過日誌發現,xorm吧沒一個字段和表名都添加上了雙引號:SELECT TOP 5 "addressid", "address1", "address2", "city", "postalcode" FROM "person.address"這個sql在mssql中執行是沒問題的,但是放到達夢數據庫中就會報錯,因為達夢不支持雙引號包裹字段、命名空間、表名:

這樣就很坑爹了,我嘗試着修改結構體的xorm:"addressid"去掉其中的雙引號,但是問題還存在,最後想到打印出來的sql中待了雙引號,說明xorm後台還是拼接的sql語句,如果找到拼接sql語句的代碼然後去掉其中的雙引號不是就好了么。於是跟蹤代碼查找拼接sql的代碼:

解決方式一)

1、engine.Table("person.address").Limit(5, 0).Find(&sliceOfAddress)

先找到engin模塊的Find()方法:

代碼路徑:src.github.com/go-xorm/xorm/engine.go

// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
	session := engine.NewSession()
	defer session.Close()
	return session.Find(beans, condiBeans...)
}

發現其實調用的是session.Find() 方法

2、src.github.com/go-xorm/session_find.go

// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
	if session.isAutoClose {
		defer session.Close()
	}
	return session.find(rowsSlicePtr, condiBean...)
}

發現實際上調用的是session.find(rowsSlicePtr, condiBean...)

func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
	
	defer session.resetStatement()

	// 代碼省略 。。。

	var sqlStr string
	var args []interface{}
	var err error
    // 此處就是拼接sql的代碼
	if session.statement.RawSQL == "" {
		// 代碼省略 。。。
	} else {
		sqlStr = session.statement.RawSQL
		args = session.statement.RawParams
	}
    // 獲得配置信息判斷當前數據庫類型
	uri := session.engine.Dialect().URI()
	// 判斷當前是否是達夢數據庫
	if uri.DbType == "mssql" && uri.DbName == "DM" {
		newSqlStr := strings.Replace(sqlStr, "\"", "", -1) // 去掉雙引號
		sqlStr = newSqlStr
	}

	// 代碼省略 。。。
	return session.noCacheFind(table, sliceValue, sqlStr, args...)
}

通過session.engine.Dialect().URI()獲得配置信息,這段代碼怎麼來的,實際上是在xorm.NewEngine()的時候會解析配置信息,並賦值給enginedialect屬性,代碼位置:src.github.com/go-xorm/xorm/xorm.go

engine := &Engine{
		db:             db,
		dialect:        dialect,
		Tables:         make(map[reflect.Type]*core.Table),
		mutex:          &sync.RWMutex{},
		TagIdentifier:  "xorm",
		TZLocation:     time.Local,
		tagHandlers:    defaultTagHandlers,
		cachers:        make(map[string]core.Cacher),
		defaultContext: context.Background(),
	}

找到sql之後去掉雙引號即可,因為做了判斷只有是達夢的類型數據庫的時候才修改,所以不會影響其他類型的數據庫。至此問題得到了解決。

解決方式二)

上面的方式一是一種解決方案,其實有更簡便的,因為我們在創建engine的時候已經確定了dialect類型為dialect_mssql,找到src.github.com/go-xorm/xorm/dialect_mssql.go找到方法Quote稍作修改即可:

func (db *mssql) Quote(name string) string {
	fmt.Println("Quote -> ", db.URI().DbName) // DM
	if  db.URI().DbName == "DM" { // 如果是達夢數據庫不添加雙引號
		return name
	}
	return "\"" + name + "\""
}

這樣,是在拼接SQL之前修改了邏輯,二方式一是在拼接之後再去掉引號,方式二更方便一點。
注意:
查閱最新的文檔,發現最新的xorm.io/core v1.0.1版本已經支持使用engine.Dialect().SetQuotePolicy(core.QuotePolicyNone)來設置引號策略。如果你使用的是該版本,直接設置即可。
Dialect結構體、QuotePolicy常量值
輸出結果:

[xorm] [info]  2020/06/08 17:14:18.061667 PING DATABASE odbc
[xorm] [info]  2020/06/08 17:14:19.315349 [SQL] select addressid, address1, address2, city, postalcode from person.address limit 5 offset 2
0       ADDRESSID=3     ADDRESS1=青山區青翠苑1號        ADDRESS2=       CITY=武漢市青山區       POSTALCODE=430080
1       ADDRESSID=4     ADDRESS1=武昌區武船新村115號    ADDRESS2=       CITY=武漢市武昌區       POSTALCODE=430063
2       ADDRESSID=5     ADDRESS1=漢陽大道熊家灣15號     ADDRESS2=       CITY=武漢市漢陽區       POSTALCODE=430050
3       ADDRESSID=6     ADDRESS1=洪山區保利花園50-1-304 ADDRESS2=       CITY=武漢市洪山區       POSTALCODE=430073
4       ADDRESSID=7     ADDRESS1=洪山區保利花園51-1-702 ADDRESS2=       CITY=武漢市洪山區       POSTALCODE=430073
*******************************
[xorm] [info]  2020/06/08 17:14:19.324291 [SQL] SELECT TOP 5 addressid, address1, address2, city, postalcode FROM person.address
0={1 洪山區369號金地太陽城56-1-202  武漢市洪山區 430073}
1={2 洪山區369號金地太陽城57-2-302  武漢市洪山區 430073}
2={3 青山區青翠苑1號  武漢市青山區 430080}
3={4 武昌區武船新村115號  武漢市武昌區 430063}
4={5 漢陽大道熊家灣15號  武漢市漢陽區 430050}

參考文檔

xorm的操作指南

xorm的pkg文檔

go語言中文文檔

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

【其他文章推薦】

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!