1.ioså¼å常è¯
2.如何通过玩TensorFlow Playground来理解神经网络
3.swift 教程 swift介绍
4.Context 使用场景&&源码解读
5.深入研究ast-grep的源码模式: 一文解析Tree-Sitter核心概念
6.Vue3源码解析(computed-计算属性)
ioså¼å常è¯
1.IOSå¼åè¦å¦ä¹ åªäºæ¹é¢çç¥è¯
æ¥èªç½åççæ¡ï¼è¯·åè
第ä¸æ¥ï¼ç¼ç¨å ¥é¨è¯¾
æ¶é´é¢è®¡ï¼4个ææ
æ¨èçå ¬å¼è¯¾ï¼Udacityä¹è¡ï¼ç½æå ¬å¼è¯¾ä¹è¡ï¼èªå·±æ¾ä¸ä¸ªé¢å¯¹å¯¹è±¡è¯è¨ï¼ä¸è¬æ¯JAVA, C++, Pythonï¼ç课ãææ¯å¨ç½æå ¬å¼è¯¾ççæ¯å¦ç¦çCSAï¼å¦çJAVAã
å¦æä½ çº¯ç²¹å¦iOSå¼åï¼ä¸æ¨èçåä½CS,CSæ¯ç»CSç³»çå¦çä»ç»æ´ä¸ªè®¡ç®æºä¸ççæ¡æ¶ï¼è®²çå 容æ¯è¾å¤ï¼è¿åº¦æ¯è¾å¿«ï¼å¯¹iOSå¼åå ¶å®æç¹ç´¯èµäºãï¼è£å¦¾æç¹è·ä¸ä¸åï¼ï¼ï¼
计åå®ææ¯ä¸å¤©ä¸è¯¾ï¼ç课ç¨è¦æ±ç书ï¼è³å°çå®ä¸æ¬ï¼å大é¨åä½ä¸ãè¿ä¸é¶æ®µéç¹ä¸æ¯è¯æ³ï¼èæ¯ä»¥ä¸3个ç®æ ã
ç®æ ï¼
1. 让èªå·±å¯¹ç¼ç¨è¿ä»¶äºæå°éåºã
åhello worldã
æä¹åfunctionï¼ æä¹è°ç¨functionã
å ¨å±åéï¼å±é¨åéè¿ç±»åºæ¬ç¥è¯ç¹ã
é½æ¯åºæ¬çä¸è¥¿ãçç书ï¼åå¤ä¸¤ä¸ªç¨åºå°±æ¬§å¦ã
2. ææ¡ç¼ç¨è¯è¨çåºæ¬è¦ç´ ã
ç¼ç¨è¯è¨4个è¦ç´ ï¼
a. åºæ¬çæ°æ®ç±»åï¼æ´æ°ï¼å®æ°ï¼character, string, boolean
b. åºæ¬çè¿ç®ç¬¦å·ï¼+-*/><ï¼++--é£å¥ç
c. ææ ·è¾å ¥è¾åº
d. ææ ·æ§å¶ç¨åºï¼sequence,selection,loop
3. äºè§£ç¼ç¨èå¼
é¢å¯¹è¿ç¨ç¼ç¨ã
é¢å对象ç¼ç¨ã
第äºæ¥ï¼ä¸æiOS!
æ¶é´é¢è®¡ï¼2ææ
强çæ¨èCSPï¼è头å讲çè¶ çº§å¥½ï¼æçå¾å¤ä¸è¥¿ï¼å¯¹è±¡æç»´å¥çï¼æ¯å¨è¿éè·çåç»ä¹ çæ¶åæçæ£æç½çï¼å¥½å¦ï¼ä¹å¯è½æ¯ä¸ä¸å 课ç»ä¹ åå¾å°çåå ï¼ãå¦æçå°9æåºè¯¥itunes Uä¸ä¼å¼å§æiOS 7äºãç½æå ¬å¼è¯¾çæ¯å¹´iOS 5ççï¼åå 课ï¼ä¹è¡ãï¼iTunes Uä¸æå®æ´ç课ï¼
CSP说æprerequisiteï¼ä¸å¼å§è¢«åå°ï¼äºå®è¯æè¿æ¯å¯ä»¥å¦ä¸å»çã头两è课ä¸å¤´é¾æ°´ï¼æ²¡å ³ç³»ï¼æitunes Uä¸ç课件ä¸è½½ä¸æ¥ï¼æææ代ç æåºæ¥ï¼ç¶åä¸ä¸ªä¸ªå ç´ å¯¹åºä¹åå¦çè¯è¨å¹é ï¼åä¸æå æ¾çï¼ç»§ç»å¦åè¾¹çï¼è¿å 天æå¤ç¹ä»£ç å°±æäºã
æè§å¦5ã6å 课ï¼ä¸ä¸ªææå·¦å³å°±å¯ä»¥å¼å§è¿å ¥ä¸ä¸é¶æ®µèªå·±åä¸è¥¿äºãä¹åç¨å¥å¦å¥ï¼æ¯å 课é½æ主é¢çãéåº¦æ ¢ç¹çåå¦ä»¬ï¼è¿é¶æ®µè·æä¸æ ·åå¤ä¸¤ä¸ªææå§ï¼
第ä¸æ¥ï¼å¼åapp!
æ¶é´é¢è®¡ï¼2ææï¼æ¬äººã1个åæï¼å®å¨ä¸å¥½ææ说åºå£ï¼
è¿ä¸ªæ¶é´å°±å¯é¿å¯çå¦ï¼è¿å æ¬ç¾å·¥ï¼äº¤äºå¥çãåæè¦ç¨å¥å¦å¥çååï¼å ¶å®å°±æ¯ç¥éiOS SDKé½æä»ä¹ç»ä»¶ï¼æ¯ä¸ªç»ä»¶æä»ä¹functionèå·²ãstackoverflow, Github, apple sample codeå¤ä¸ï¼æç´¢å¼æå¤ç¨ãå¦ææ个å¸å ï¼è¿ä¸ªé¶æ®µççæ¯è¿æ¥ç¥éã
好çï¼ä¸åºæå¤ï¼ä½ ç第ä¸ä¸ªappå°±è¿ä¹æ°é²åºçäºï¼ä»ä»å¤©å¼å§ï¼æ为ä¸ä¸ªå·è³é¼æ ¼é«å°çiOSå¼åè å§ï¼
2.å¦ä¹ iosç¼ç¨æè¦çç¥è¯åºç¡å¤§æ¦æ¯ä»ä¹
Cè¯è¨ï¼å¯ä»¥è¿ä¹è¯´ææçå¼åä¸è¦ä¹å°±ç¨å°Cè¯è¨ï¼è¦ä¹å°±è¦ç¨å°Cè¯è¨çè¯æ³ç»æï¼åæ£æä¹å¼é½ä¼åC沾边ï¼IOSä¹ä¸ä¾å¤ï¼IOSçå¼åè¯è¨æ¯objective-cï¼èobjective-cåæ¯Cçè¶ çº§ï¼æ以å¦ä¹ IOSéè¦Cçåºç¡ï¼åæ¶å¨ç¼åIOSç¨åºæ¶ä¹æ¯æC/C++æ··ç¼ï¼æ以å¦æä»äºIOSå¼åï¼å¿ é¡»å çæobjective-cè¿é¨å¼åè¯è¨ï¼å®é ä¸å°±æ¯Cè¯è¨äºã
å½ç¶å¨å¦ä¹ IOSçæ¶åï¼ä¹å¹¶ä¸æ¯å¿ é¡»æåºç¡ï¼ç®åè¿è¾¾ä¸å°æ²¡æåºç¡ä¸è½å¦çå°æ¥ï¼å ¶å®å¨ä¸å½å¹è®è¡ä¸æ¥è¯´ï¼æ 论æ¯ä»ä¹ä¸ä¸ï¼æ 论æ¯å¤ä¹é«ç«¯çè¡ä¸ï¼åªè¦æ¯å±äºå¹è®è¡ä¸ï¼å°±ä¸å®æé¶åºç¡æ课çï¼å°±ç®ä½ 没åºç¡å¦æ ¡ä¹ä¼ä¸ºä½ å è´¹è¡¥ä¹ åºç¡ã
3.æ³é®ä¸åioså¹³å°ç软件å¼å,éè¦é£äºåºç¡ç¥è¯
iOSæ¯è¿è¡äºiPhoneãiPodtouch以åiPad设å¤çæä½ç³»ç»ï¼å®ç®¡ç设å¤ç¡¬ä»¶å¹¶ä¸ºææºæ¬å°åºç¨ç¨åºçå®ç°æä¾åºç¡ææ¯ãæ ¹æ®è®¾å¤ä¸åï¼æä½ç³»ç»å ·æä¸åçç³»ç»åºç¨ç¨åºï¼ä¾å¦PhoneãMail 以å Safariï¼è¿äºåºç¨ç¨åºå¯ä»¥ä¸ºç¨æ·æä¾æ åç³»ç»æå¡ã
iOS å¼åå·¥ç¨å¸ä¸»è¦ä»äºææºæä½ç³»ç»ç ååææºåºç¨è½¯ä»¶å¼åï¼å æ¬ææºæ¸¸æçåç±»åè½ç软件å¼åï¼ãå¨åä¸è°æ¥çå¼åææ¯äººåä¸ï¼%ç称ï¼ä»ä»¬æ£å¨ iOS å¹³å°å¼å人æï¼å ¶ä¸ %çè¡¨ç¤ºï¼ iOS å¹³å°å¼åç»éªè¦æ¯ä»»ä½å ¶ä»å¹³å°å¼åç»éªæ´åéçã
ç±äºå½å iOS å¼åèµ·æ¥ç¸å¯¹è¾æï¼äººæå¹å »æºå¶æ´æ¯è¿è¿è·ä¸ä¸å¸åºåå±é度ãæéçiOS å¼å人ææäºå½å ä¼ä¸å¿ äºçèµæºãçè³æçä¼ä¸ä¸å¾ä¸èèéè¿æ¶è´æ¥å¡«è¡¥äººæ空缺ãä¸å iOS å¼åæ°æè¦æ¯æ®é软件å¼åæ°æé«åºçº¦ -%çèªèµï¼ç¬¦åæ¡ä»¶ææ项ç®ç»éªçå¼åå·¥ç¨å¸æ´æ¯æä»·æ å¸ã IOSå¼åæ¹é¢çç¥è¯ï¼å¤§æ¦æä¸ä¸å ç¹ã
1ãç¯å¢åå¤ãè¿å°±æ¯å¼ååæéçç¯å¢ï¼ç¸å ³è½¯ä»¶çå®è£ å使ç¨è¯¦è§£ãè¿éå æ¬æIOSå¼åååå¤ï¼Xcodeéæå¼åç¯å¢çå®è£ 使ç¨ä¸é¡¹ç®å»ºç«æµç¨ï¼Xcode6ä¸çPlaygroundçç¹ç¹å使ç¨æ¹æ³ï¼IOSå¼å常ç¨æä½åæå·§ï¼IOSç¨åºæå ä¸åå¸
2ãSwiftç¼ç¨è¯è¨ãå æ¬æSwiftè¯è¨åºç¡ï¼Swiftè¯è¨ä¸Objective-Cè¯è¨æ··åç¼ç¨ï¼Swifè¯è¨é¢å对象详解ï¼Swiftãè¯è¨è°è¯æå·§
3ãIOSç¨æ·çé¢ãå æ¬æIOS项ç®ä»ç»ï¼IOSç¨æ·çé¢å¼ååºæ¬åæ¨æ¶æï¼IOSè£åæ§ä»¶TableViewçå¼åä¸ä½¿ç¨ï¼ä½¿ç¨StoryBoardåIOS UIçé¢è·³è½¬ã
4ãçé¢ä¼åãå æ¬æIOSç»å¾APIç»å¶çº¿æ¡/æå/å ä½å¾å½¢ï¼Xcode常ç¨é¡¹ç®æ¨¡çï¼å±å¹éé ï¼IOSèªå®ä¹æ§å¶å®ä¾ï¼IOSçå¨ç»ææåå®ç°æ¹æ³ï¼IOSä¸çCALayeerç使ç¨ã
4.IOSå¼åè¦å¦ä»ä¹
Objective-Cé¢å对象åºç¡ï¼ç»§æ¿ï¼å¤æãå¨æç±»ååå¨æç»å®ï¼
Objective-C访é®ç³»ç»ä¸çæ件ï¼Objective-CçXML解æåçæï¼å¯¹è±¡åºååï¼
Objective-C线ç¨ååä»»å¡ï¼Objective-Cä¸çSocketåHTTPï¼å å管çï¼èµæºéæ¾ååæ¾
UIåºç¨ç¨åºå¼ååºç¡ï¼Interface Builderå·¥å ·ï¼çªå£è§å¾ï¼UIåºç¡æ¦å¿µï¼åºæ¬äº¤äº ï¼Cocoaäºä»¶ä¼ æä¸ç¸åºåºç¡ï¼å¸¸ç¨æ§ä»¶ï¼TableViewçè¾ä¸ºå¤æçæ§ä»¶ï¼æ件å åèµæºï¼å¾å½¢åé¢è²ï¼Cocoaèªå®ä¹ ç»å¶å¾ååºç¡ï¼Objective-C çå¨ç»ææå¼åï¼ Objective-Cçå¤å½è¯è¨æ¯æï¼å¨åºç¨ä¸åµå ¥æµè§å¨ä»¥å使ç¨WebServiceççã
IOSå¼åè¿è¦å¦ä¹ ä¸äºå ¶ä»çç¥è¯ï¼å ·ä½çå¯ä»¥é®é®â4G梦工åºâçèå¸ï¼å 为â4G梦工åºâéæIOSå¹è®è¯¾ç¨ï¼éé¢çèå¸å°ä¼ç»ä½ æ´ä¸ä¸ç解çã
5.ios游æå¼åå ¥é¨åºè¯¥åå¤äºä»ä¹ç论ç¥è¯
è¿ä¸ªå¤çå¤åå¤è¯å®æ¯æ²¡åå¤ç ä½ä¸ºä¸åååºè åºçiOSå¼å人åï¼å¦ä½çæç¼åiPhone åiPad游æå¢ï¼æ¨å¯ä»¥åå©ãiOS游æå¼åå ¥é¨ç»å ¸ãæ¥å¥ å®è¯å¥½åºç¡ã
æ 论æ¨æ¯å¦æ¥æiOSç¼ç¨ç»éªï¼é½å¯ä»¥åå©æ¬ä¹¦æ¥äºè§£å¼å§å建æ趣iOS游ææéçææ¯ãä¸è¿æ´ä¸ä¸çç论ç¥è¯ä½ å¯ä»¥å°åéæè²ç½ç«ä¸çç èµæå¾å ¨ç ä¹å¾æ¹ä¾¿å¦ä¹ ç°å¨iOSå¹è®æºææå¾å¤ï¼å¯æ¯ä¸å¦åç¾è®¢ãå°±ä¸å¹è®åè®®ãï¼å¨åè®®éæç¡®ååºèªæ°´ä¿éçä¼ä¸ï¼æä½èªæ°´ï¼ä¸ç§5Kèµ·ãæ¬ç§6Kèµ·ãç¡å£«8Kèµ·ï¼åéæ¯ä¸å å¯ä¸ä¸å®¶ï¼å£ç¢å¾å¥½ã
6.ä¸ä¸ªèµæ·±çiOSå¼åè éè¦ææ¡åªäºæè½
iOSå¼åè½å
ææ¡ï¼æ好æ¯ç²¾éï¼OCè¯è¨åruntimeåç§ç»èï¼è¯»è¿ç¸å ³çclangæºç åruntimeæºç 为佳ï¼ãç²¾éåºæ¬çframework(Foundation,UIKitçï¼å¹³æ¶å¹²æ´»ç¨å¾æå¤ç)ãææ¡ä¸äºç¬¬ä¸æ¹çè½®åï¼è¿ä¸ªä¸»è¦çä½ çå·¥ä½ç»éªåä¹ æ¯ï¼å¦æèªå·±ææè¿ä¸éçè½®åæ好ï¼è¿ç¹å¯ä»¥çåºä½ çç»éªï¼ç¼çå解å³é®é¢çè½åãï¼
åºç¡ç¥è¯
å¦æ ¡éçé£äºç»å ¸è¯¾ç¨ï¼æ°æ®ç»æï¼ç®æ³ï¼ä¸å¤§æµªæ¼«åºç¡ï¼ååæ¯ç 究é¢åçåºç¡è¯¾ç¨ï¼ï¼è¿äºåæ£é½æ¯èç常è°äºãããä¸å¥½å¥½æåºç¡åªè½ä¹¦å°ç¨æ¶æ¹æ¨å°äºãå³ä½¿åä¸å°ç²¾éï¼è³å°åºè¯¥äºè§£å个åºç¡ç¥è¯çå ³ç³»åå ¥å£ç¹ï¼ç¥è¯ä½ç³»ç»æï¼ï¼å°±åä½ åooæ¶å»ºç«çç±»å±æ¬¡ç»æã
å¦ä¹ è½å
è½æ ¹æ®èªå·±çå·¥ä½ç®æ å¿«éçè°ç ãææ¡ãæ¹è¿å山寨åç§ææ¯ï¼å¹¶ä¸è½æåç§ç¸å ³ç¥è¯ç¹èåèµ·æ¥ï¼äº§çæ°ææ¯ï¼æ¨å¨ææ¯åå±ã
æç´¢æè½ï¼å ¶å®å¾å¤äººä¸ç¥éèªå·±è¦æ¾ä»ä¹åå¦ä½å»æ¾ï¼å°åªå»æ¾
æé®æå·§ï¼è½æ¸ æ°ç表达èªå·±çæå¾ï¼å¥½è®©å«äººç¥éæä¹å¸®ä½ ï¼è¯·æç´¢âæé®çèºæ¯â
广ä¹çå¼åè½å
ä¸ä» éäºiOSï¼è¦å¨ææ¯ä¸ææ建æ ï¼è¿æ¯éè¦å¼éèªå·±çç¼çï¼ä»ä¸åé¢åæ±²åè¥å »ï¼å¼éç¼çï¼æè°çå ¨æ åè·¨çæ£æ¯å¦æ¤ã
æææ¯ç人è¦æä¸é¢â好å¥å¿âã
å·¥ç¨è½å
åç§å·¥å ·ï¼VSC,CI,Issue Tracking,Testing,Profilingï¼ä½¿ç¨ï¼è®¢å¶æ¹è¿ï¼å¼åãè¿äºç®å å项ï¼åç使ç¨å¯ä»¥æææé«å¼åæçã
éæ±è½åï¼å¯ç解ï¼å¶å®åæ¹è¿åç§ææ¯éæ±ï¼ä¸å¡éæ±ã
ææ¡£è½åï¼åç§ææ¡£åç»å¾å·¥å ·ï¼åäºè¡¨è¾¾åæ»ç»ï¼æ好æ¯å¤å¤å享ï¼æé«âç¥å度âåâå½±ååâ
管çè½å
管çèªå·±ï¼å¯ä»¥æèªå·±å¾æ¢å®ç®æ ææ¡ä¸ç´çåè¿ï¼éå°çªåäºä»¶è½æä¼å 级è°æ´å¹¶å®æ½æ°è®¡åã
管çå¢éï¼é¦å æ¯ä¸è§ç«¯æ£ï¼æä¸å®ç亲åååå½±ååï¼è½ææçååäºå°±é®é¢è¿è¡å讨ï¼æä¸å®ç说æè½åï¼å¯ä»¥ä»£é¢èº«è¾¹åäºä¸èµ·å¾æ£ç¡®çæ¹ååè¿ã
å¦å¤éä¸ä¸å¼ å¦ä¹ å¾ï¼å¸æè½å¤å¸®å©ä½ ï¼
如何通过玩TensorFlow Playground来理解神经网络
单个神经元的数学机制很简单,它所能做的源码只是将数据点分成两类。而众多神经元组成的源码深度神经网络能提取更多特征,解决更复杂更抽象的源码问题。(之前相关报道:业界 | 想揭开深度学习隐藏层的源码神秘面纱?试试Tensor Flow的神经网络游乐场)源码:htt如何通过玩TensorFlow Playground来理解神经网络
swift 教程 swift介绍
1、要使用swift须拥有一台苹果电脑。源码网页源码找视频因为集成开发环境XCode只能运行在OS X系统上。源码电脑系统必须在OS .9.3及以上,源码电脑必须安装Xcode集成开发环境。源码
2、源码下载完成后,源码双击下载的源码 dmg 文件安装,安装完成后我们将 Xcode 图标踢移动到应用文件夹。源码Xcode 安装完成后,源码就可以开始编写 Swift 代码了。源码接下来我们在应用文件夹打开 Xcode,打开后在屏幕顶部选择 File => New => Playground。接着 为 playground 设置一个名字并选择 iOS 平台。
3、如果你想创建 OS x 程序,需要导入 Cocoa 包 import Cocoa以上程序载入后,会在Playground 窗口右侧显示程序执行结果。
4、选择一个Single View Application,并点击next,创建一个简单示例app应用。
5、接着我们输入项目名称(ProductName),公司名称(Organization Name),公司标识前缀名(Organization identifier) 还要选择开发语言(Language),选择设备(Devices)。其中Language有两个选项:Objective-c和swift,因为我们是学习swift当然选择swift项了。 点击Next下一步。
6、选择存放的目录,如果要使用Git源代码管理,将勾上Source Control的create git repository on My Mac. 点击create创建项目。
7、项目创建后,默认生成了一个示例文件,可以看到swift将oc中的h和m文件合并成了一个文件(即swift后缀名文件). Main.storyboard相当于xib文件,有比xib更多的功能。
8、打开main.storyboard,默认看到一个简单的空白的应用界面,大小为平板界面大小。 如果开发都只需要开发兼容iphone手机的app,那么可以把Use Auto Layout的勾去掉(默认为勾上)。弹出了一个对话框,让我们选择界面尺寸,iPhone 或 iPad。我们选择iPhone的尺寸。
9、界面添加点内容,在右下方找到Text控件,将它拖入storyboard上,并双击写入文本Hello World!
、运行一下模拟器(command+R 快捷键或在菜单栏中选择 Product => Run)。
至此,第一个Swift项目就完成了。
、swift介绍
《Swift》是一种支持多编程范式和编译式的开源编程语言,苹果于年WWDC(苹果开发者大会)发布,用于开发 iOS,OS X 和 watchOS 应用程序。 Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。 Swift 在 Mac OS 和 iOS 平台可以和 Object-C 使用相同的运行环境。 年6月8日,苹果于WWDC 上宣布,Swift将开放源代码,包括编译器和标准库。
Swift 是一种全新的编程语言,结合了 C 和 Objective-C 的优点,并且不受C兼容性的限制。Swift 采用的安全编程模式添加了很多新特性,这使得编程更简单,更灵活,也更有趣。Swift 在 Foundation 和 Cocoa的基础上构建框架,并且采用了很多 Objective-C 的虾皮源码命名参数以及动态对象模型,并且支持过程式编程和面向对象编程。Swift 将现代编程语言的精华和苹果工程师文化的智慧结合了起来,既能够开发简单的小程序,也能够构建出一套完整的操作系统。
Context 使用场景&&源码解读
本文深入探讨了Go语言中的Context机制及其在协程生命周期控制、参数传递和超时管理等场景的应用。 Context是Go语言中用于管理和控制协程生命周期、传递全局参数的重要工具。它为开发者提供了灵活的机制,以实现协程的取消、超时控制和公共参数的传递,从而提高了程序的健壮性和可维护性。 下面,本文将分几个部分详细介绍Context的使用场景和源码解读,以帮助读者更好地理解和应用这一机制。Context的使用场景
1. **协程生命周期控制**:通过Context,可以实现对协程的取消操作,即在必要时停止协程的执行,避免资源的浪费和死锁现象。2. **超时控制**:在执行耗时操作时,Context可以设置超时机制,一旦超时,将自动停止执行并返回错误,避免阻塞系统。
3. **请求跟踪与参数传递**:在多层调用或服务链路中,Context可用于传递请求ID、用户信息等全局参数,方便跟踪请求状态和上下文信息。
Context源码解读 1. **Context接口**:定义了Context的主要方法,如Deadline、Done、Err和Value,用于获取截止时间、取消状态、错误和值等信息。2. **canceler接口**:定义了可取消Context的方法,如cancel方法,用于向后代Context传递取消信号。
3. **cancelCtx结构体**:作为实现Context的核心,包含父Context、只读的无缓冲通道Done、错误信息err和直属后代Context的map children。
Context调用链路与Demo 本文详细展示了Context的调用链路,包括Background、TODO、WithValue、WithCancel、WithDeadline和WithTimeout等方法的使用场景和效果。通过这些方法,开发者可以根据具体需求构建灵活的Context树,实现协程的精细控制和参数传递。Context Demo
本文提供了一个Go Playground直接运行的Demo代码,展示了如何在实际应用中使用Context进行HTTP请求超时控制和主动取消操作。通过引入Context,开发者可以在发送HTTP请求时设置超时时间,一旦请求超时,程序将收到错误响应并中断,从而避免了长时间等待或系统阻塞的问题。 总之,Context机制在Go语言中扮演了关键角色,为开发者提供了高效、灵活的协程管理和控制手段,有助于构建更健壮、高效的并发程序。深入研究ast-grep的模式: 一文解析Tree-Sitter核心概念
如果你对代码重构工具有兴趣,你可能听说过 ast-grep,它是一个基于 Tree-sitter 的工具,可以进行结构搜索和替换。 ast-grep 允许你编写代码模式,根据代码的结构,而不仅仅是文本来查找和修改代码。但它是如何在引擎盖下工作的呢?在这篇文章中,我将为你深入介绍ast-grep的模式。它还能帮助你理解Tree-sitter的TDM源码核心概念。
模式是一种写和读描述语法树的表达式的方便方法。 它类似于代码,但有一些特殊的语法和语义,允许你根据语法树的结构、类型或内容来匹配部分。
ast-grep的模式易学难精。它要求你了解目标语言的Tree-sitter语法和含义,以及ast-grep的规则和惯例。
在本文中,我们将帮助你掌握所有基于Tree-sitter的工具所共有的核心概念。我们还将向你展示如何编写ast-grep模式,让它的全部威力都为你所用。
什么是Tree-sitter? ast-grep使用 Tree-sitter作为它的底层解析框架,这是因为它的流行度、高性能和健壮性。
Tree-sitter是一个生成解析器的工具,并提供一个增量解析库。
解析器是一个将源代码文件作为输入并产生一个描述代码组织的树状结构的程序。(该树状结构不是抽象语法树,我们将在后面看到)。
为各种编程语言编写优秀的解析器是一项艰巨的任务,尤其是对于像ast-grep这样的单一项目。幸运的是,Tree-sitter是一个被社区广为传唱的好工具。许多主流语言,如C、Java、JavaScript、Python、Rust等,都被Tree-sitter支持。使用Tree-sitter作为ast-grep的底层解析库,可以让这个工具支持任何具有良好维护的语法的语言。
Tree-sitter的另一个好处是它的增量性质。增量解析器是指当源代码文件被编辑时能够有效地更新语法树的解析器,而不需要重新解析整个文件。在 ast-grep的交互式编辑中,它可以非常快速地运行在每一个代码变化上。
最后,Tree-sitter还可以优雅地处理语法错误,它可以在同一个文件中解析多种语言。这使得模式代码的解析更加稳健,更容易编写。在未来,我们还可以像Vue那样支持多语言的源代码。
当你使用 ast-grep 来搜索源代码中的模式时,你需要了解文本匹配和结构匹配之间的区别。
源代码输入是文本,是遵循某些语法规则的字符序列。你可以使用常见的搜索工具,如 silver-searcher或 ripgrep来搜索源代码中的文本模式。
然而,ast-grep并不直接与文本匹配模式。相反,它将文本解析成一个代表代码语法的树状结构。这使得ast-grep能够根据代码的语义来匹配模式,而不仅仅是其表面现象。这就是所谓的 结构搜索,它搜索的是具有特定结构的代码,而不仅仅是特定的文本。
因此,你写的模式也必须是有效的语法,可以与代码树进行比较。
ast-grep中的文本搜索 虽然pattern在结构上匹配代码,但你可以使用ref=" ast-grep.github.io/guid...">原子规则regex通过指定正则表达式来匹配节点的文本。这样,就可以在ast-grep中结合文本和结构匹配。
我们可以用两种类型的树结构来表示代码的语法和语义: AST和CST。
AST代表 抽象语法树,它是代码的简化表示,省略了一些细节,如标点符号和空白处。CST代表 具体语法树(Concrete Syntax Tree),它是源码 路灯对代码的一种更保真的表示,包括所有的细节。
Tree sitter是一个库,可以将代码解析为许多编程语言的CST。因此,ast-grep与它的名字相反,是根据CST模式而不是AST来搜索和重写代码的。
让我们通过一个例子来看看为什么CST更有意义。考虑一下1 + 1这个JavaScript片段。它的AST表示法 看起来像这样:
精明的读者应该注意到重要的运算符+并没有在AST中被编码。与此同时,代码的CST则忠实地表达了所有的关键信息。
你可能会想,使用CST是否会让不重要的空白影响你的搜索结果。幸运的是,ast-grep使用了一种智能匹配算法,可以在适当的时候跳过CST中的琐碎节点,帮你节省了很多麻烦。
如果不关心标点符号和空白,我们就可以将CST转换为AST。Tree-sitter有两种类型的节点:命名节点和匿名节点(未命名节点)。
更重要的命名节点在语法规则中被定义为常规名称,如binary_expression或identifier。不太重要的匿名节点是用字面字符串定义的,如", "或 "+"。
命名节点对于理解代码的结构和意义更为重要,而匿名节点则不那么重要,有时会被 ast-grep 的匹配算法跳过。
下面的例子改编自 Tree-sitter的官方指南,显示了语法定义的不同。
实际上,命名的节点有一个叫做kind的属性,表示它们的名字。你可以使用ast-grep的ref=" ast-grep.github.io/guid...">原子规则kind来找到具体的AST节点。下面的例子的 Playground链接。
更进一步,ast-grep的元变量默认只匹配命名的节点。return $A 只匹配下面的第一条语句。 Playground链接。
我们可以使用两个米元符号(非笔误)$$VAR在模式匹配的结果中包括匿名节点。return $$A将匹配上面的两个语句。 Playground链接。
有时,仅仅使用kind并不足以找到我们想要的节点。一个节点可能有几个具有相同kind的子节点,但在代码中的作用不同。例如,在JavaScript中,一个对象可能有多个键和值,但它们都可以是字符串。
为了区分它们,我们可以使用field来指定一个节点和它的父节点之间的关系。在ast-grep中,field可以用在两个 关系规则中:has和inside。
has和inside接受一个特殊的配置项,叫做field。field的值是父-子关系的字段名。例如,JavaScript对象中的键值对有两个孩子:一个字段是key,另一个字段value。我们可以用 这个规则来匹配string的key节点。
field可以帮助我们缩小搜索范围,使模式更加精确。
我们也可以用has重写上面的规则,搜索带有字符串key的键值对。 Playground链接。
kind和field的关键区别: kind是节点本身的属性。只有命名节点才有。 field是父子关系的属性。匿名节点也可以有。
一个节点同时拥有kind和field可能会让新用户感到困惑。kind属于节点本身,在ast-grep的Playground上用蓝色文本表示。子节点只有相对于它的父节点才有field,反之亦然。模组源码字段在Playground中用深**文本表示。由于field是节点关系的一个属性,匿名节点也可以有field。例如,binary_expression的1 + 1中的+的field就是operator。
ast-grep比Tre-sitter走得更远。它有关于节点的 "重要性 "的概念。
即使是“重要性”这个概念也是不够的。 大多数Tree-Sitter语言没有在命名节点AST中编码所有的关键语义。即使我们定义了范围更广的显著节点,也不足以表示代码的意义。我们必须保留一些琐碎节点来进行精确匹配。
Tree-sitter一般不会用命名节点来编码所有的语义。例如,class A { get method() { } } 和 class A { method() { } } 在Tree-sitter的AST中是等同的。关键标记get没有命名,也没有field。它是一个琐碎节点!
如果你不关心这个方法是getter方法、静态方法还是实例方法,你可以使用class $A { method() { } }来 一次性匹配所有三种方法。如果你需要区分getter方法和普通方法,你可以 拼出完整的方法修饰符。
感谢你阅读到这里! 这篇文章中有许多概念。让我们用一段话来总结一下。
ast-grep使用Tree-sitter将文本源代码解析成一个详细的树状结构,称为CST。我们可以从CST中得到AST,只保留命名节点,这些节点有kind。为了搜索语法树中的节点,可以同时使用节点kind和节点field,后者是一个子节点相对于其父节点的特殊标记。一个有kind或者有field的节点就是一个重要的节点。
Vue3源码解析(computed-计算属性)
作者:秦志英Vue3计算属性源码解析
在理解了Vue3响应式系统后,我们继续深入剖析其核心组件——计算属性的实现机制。Vue3中的计算属性通过computed函数提供API,让我们通过源码来揭示其内部运作。 在ComputedRefImpl类中,有两个关键私有属性:_value用于缓存计算结果,_dirty用于标记是否需要重新计算。当属性值改变时,会触发trigger函数,遍历并执行依赖的effect函数。如果effect配置了scheduler,那么计算属性的getter并不会立即执行,而是设置_dirty为false,并通知依赖的副作用函数。 构造函数中,我们会包装getter函数为effect,并将其添加到依赖集合中。同时,lazy和scheduler参数控制了计算属性在何时调度。让我们通过一个示例来看计算属性的完整流程:当点击按钮改变testData时,计算属性的更新流程如图所示。总结:计算属性特性
计算属性的主要特性包括:其值依赖于其他属性的更新,但只有在必要时才会重新计算,且通过lazy和scheduler配置实现灵活调度。如果你对Electron感兴趣,不妨关注我们的开源项目Electron Playground,了解更多技术知识。 我们是好未来·晓黑板前端技术团队,持续分享最新技术动态。关注我们:知乎、掘金、Segmentfault、CSDN、简书、开源中国、博客园。PolarDB-X 源码解读(七):私有协议连接的一生(CN篇)
通过前文的介绍,大家基本了解了一条SQL在polardbx-sql中的解析和执行流程。由于polardbx-sql是无状态的计算节点,真正数据需要从存储节点传输到计算节点,这部分工作由私有协议完成。本文将详细介绍从发送请求到存储节点,接收返回数据的完整流程,重点在于私有协议连接的生命周期和关键代码解析。
概述
为了提高数据节点本地计算能力,同时减少网络数据传输量,计算节点会尽可能下推计算内容。一个逻辑表可能需要多个物理分片,因此计算节点与存储节点的请求会话数量会随着分片数增加而增加。传统MySQL协议+连接池架构已不能满足PolarDB-X的需求,因此私有协议在这一需求场景下应运而生。
如图所示,私有协议采用连接与会话分离的RPC协议设计理念,支持多个会话在同一个TCP通道中并行运行,具备流控机制、全双工响应式工作模式和高吞吐、可扩展等特性。
更多关于私有协议解决上述问题的设计详情,可以参考《PolarDB-X私有协议设计》一文。本文主要从代码层面详细描述私有协议的工作流程。
我们将从计算节点和存储节点两个角度完整解析私有协议连接的生命周期。篇幅限制,本文仅关注计算节点上私有协议的处理,存储节点部分将在后续文章中详细说明。
计算节点
计算节点作为私有协议的客户端,负责发送下推请求,并接收返回的数据。
网络层框架
PolarDB-X私有协议网络层采用定制化Reactor框架实现,基于Java的NIO,改进自polardbx-sql中的Reactor框架。网络层初始化时,设置CPU核心数的2倍(上限为)作为NIOProcessor,每个Reactor使用独立的堆外内存池作为收发包缓冲,总缓冲内存大小限制为堆内存大小的%。
NIO接收的包直接调用注册的处理函数,发送数据仅写入send buf,网络写入由单独线程完成。线程优先写入TCP send buf,当无法写入时,注册OP_WRITE事件等待可写后再写入剩余内容。
数据包的编码和解码在NIOClient中实现。为实现最佳性能,解包流程直接在堆外内存上进行,使用protobuf对流直接解析,将结果放入堆内。堆外内存被切分为KB chunk,每个Reactor独占一个chunk,连续解析和复用,最大化接收、解析效率。对于特大包,额外构造堆内大buffer接收和解析,回退标志在定时任务中重置,连续s无超大包时释放堆内内存,恢复高性能堆外KB buffer接收。
请求发送集成在NIOClient中,writer优先尝试写入发送缓冲队列尾部的buffer,不足时新申请buffer填充并追加到队尾。buffer来自预分配的堆外缓冲池,超过chunk大小时分配堆内buf进行序列化。
同时,NIOClient负责TCP连接的建立和断开资源释放,作为独立的底层网络资源管理实现。
连接及会话
网络层之后,我们聚焦连接与会话分离的具体实现。通过剥离连接及收发包的具体实现,连接和会话的管理变得更加清晰简洁。
首先,一个TCP连接的逻辑抽象结构在XClient中实现,为避免误解,取名为client与JDBC中的Connection区别。该类管理TCP连接和并行运行的会话,负责TCP完整生命周期的管理、认证鉴权,并维护公共信息。其中,workingSessionMap记录了连接上并行运行的所有会话映射关系,可快速通过会话ID找到对应的会话抽象结构XSession。
XSession提供了所有会话相关的请求函数和信息存储,包括执行计划请求、SQL查询请求、SQL更新请求、TSO请求、会话变量处理、数据包处理及异步唤醒等。
连接池及全局单例管理器
为了提高性能,TCP连接和会话的复用必不可少。由于连接和会话的解绑,连接池不仅缓存了到计算节点的TCP连接,也缓存了到计算节点的会话。
XClientPool管理到一个存储节点的连接池,通过IP,端口,用户名三元组唯一确定目标存储节点,同时存储该节点的全部TCP连接(XClient)和建立的会话(XSession)。
XClientPool实现存储节点会话获取,对应JDBC接口中的getConnection,同时实现连接和会话生命周期管理、连接探活、会话预分配等功能。实现单个存储节点连接池后,XConnectionManager维护目标存储节点三元组到实例连接池的映射,管理定时任务线程池,实现定时探活、会话&连接最长生命控制以及连接池预热等功能。
JDBC兼容层
新的SQL协议层对上层使用者要求较高,为了提高开发效率,私有协议提供兼容JDBC的使用方法,实现从JDBC平滑切换至私有协议,并支持协议热切换。
JDBC兼容层代码目录在compatible目录下,Connection继承在XConnection文件中。提供包括DataSource、Connection、Statement、PreparedStatement、ResultSet、ResultSetMetaData在内的大部分常用接口函数实现,不支持的函数会明确抛出异常避免误用。
整体关系
至此,私有协议计算节点端的大部分结构已说明完成。给出一个整体的关系图。
私有协议连接的一生(CN视角)
了解了私有协议各层实现后,我们以发到存储节点的请求为例,完整梳理执行流程。绕开计算节点复杂流程,直接运行代码示例(注:需将com.alibaba.polardbx.rpc.XConfig#GALAXY_X_PROTOCOL设置为true)。
直接运行playground看到预期的select 1的结果。接下来,我们深入跟踪说明。
数据源初始化
要使用私有协议,需要初始化对应存储节点的XDataSource。构造过程中,XDataSource会到XConnectionManager注册新的实例连接池,已存在的连接池引用计数加一。
获取Connection
当需要执行查询时,首先获取会话。无论是显式开启事务还是使用auto commit事务,会话都是执行请求的最小上下文。通过XDataSource的getConnection方法获取到对应存储节点的会话。XDataSource根据存储的IP,端口,用户名三元组查找到XConnectionManager中的连接池,在最高并发检查后,会话获取逻辑在XClientPool实现。首先尝试在空闲会话池中拿会话,通过重置检查和初始化后返回给调用者。大部分场景下,ConcurrentLinkedQueue提供较好的并发性能。
在代码场景下,数据源刚新建,后台定时任务未运行,流程进入连接创建流程。会有一把大锁锁住连接池,在TCP连接未达上限且没有超时的情况下,快速新建一个XClient占坑。若超限,则进入busy waiting循环。真正的TCP connect(waitChannel)在锁外被调用,首先client以阻塞模式带超时方式connect,然后切换为非阻塞模式,round robin策略注册到NIOProcesser上,返回时,TCP连接已建立。
为了兼顾安全和性能,连接鉴权在TCP建连后只用做一次,会话创建不需要鉴权。鉴权在initClient中完成,发送SESS_AUTHENTICATE_START_VALUE包,后续校验由回调完成。认证采用标准的MySQL认证流程,server端返回challenge值,库名、用户名和加盐hash后的密码返回给MySQL即可完成认证。
至此,到存储节点的TCP连接已建立,创建会话是一个异步流程。在创建新XClient时,XConnection已new好,通过下断点跟进去可看到newXSession流程,分配session id,设置状态为init,将XSession绑定到XConnection上。
最后,XConnection经过初始化(重置auto commit状态)、重置默认DB、默认字符集(lazy操作)和统计信息记录,返回给用户使用。
发送查询请求
拿到初始化好的兼容JDBC的Connection,为了简化流程,直接调用XConnection中的execQuery。XConnection的execQuery包装了XSession的execQuery,执行前执行了设置流式模式。
首先记录调用信息进行统计,进入关键的initForRequest流程。XSession初始化流程lazy,仅分配session id,设置状态为Init,真正创建session时发送SESS_NEW给server,绑定新session和session id。如果session已复用,则状态为Ready。
执行字符集更改的lazy操作,session可能在其他请求中切换字符集,根据目标字符集和当前字符集对比,决定是否发送额外的字符集更改请求。
经过一系列变量设置、lazy DB设置和protobuf包构造,请求发送到存储节点执行。发送后,同步生成XResult负责结果解析,同时XResult按照请求顺序依次拉链表,确保结果与请求一一对应。
请求流水线结构如下图所示,处理完成前序请求后,才能解析后续结果。
接收结果集
请求已发送到存储节点执行,拿到XResult,通过XResult收集查询结果集。XResult与发送请求一一对应,存储节点处理也是在会话上排队进行,不会影响流水线上其他请求的返回,保证流水线正常工作。
首先,查看结果集处理的状态机,主要状态包括获取元数据、获取数据行、获取额外信息等,顺序固定,根据请求类型,部分环节可能被省略。报错处理贯穿整个状态机,任何报错信息都会导致状态机进入错误处理环节。
对于非流式数据读取,请求结束时主动调用finishBlockMode将所有数据读出并缓存到rows中。对于流式执行的情况,结果集状态机消费数据包队列由XResult的next函数推动,内部函数internalFetchOneObject递归调用前序XResult,消费前序请求结果,从数据包队列中消费并推动状态机流转。
对于查询,首先收到RESULTSET_COLUMN_META_DATA包,表示返回数据列定义,一个包表示一列。元数据包后,收到包含数据行的RESULTSET_ROW包,一个包对应一行。数据行传输完成后,server端发送RESULTSET_FETCH_DONE标示数据发送完成。请求结束前,NOTICE包用于告知客户端rows affected等信息。最后,SQL_STMT_EXECUTE_OK包标示请求结束。
至此,完整请求处理完成,控制台应显示查询结果。
总结
本文详细描述了私有协议连接流程中的关键点和关键数据结构,相信通过本文描述,大家掌握了私有协议连接流程的基本点,在调试和修改使用中能够更加得心应手。虽然本文篇幅较长,但实际使用中涉及更多高级特性的使用,如多请求流水线、流控、执行计划传输、chunk结果集传输等。通过本文,我们对私有协议连接流程有了深入理解,为在实际场景中应用提供坚实基础。
谈一谈 ABI, C++ ABI, Rust ABI 的稳定性 (下)
本文撰写于年9月2日。
在上一篇文章中,我们讨论了C++的ABI稳定性。实际上,Rust的ABI稳定性也有着类似的含义。我们所说的ABI稳定性,指的是同一套代码的二进制在不同编译器下能够相互兼容。
目前,Rust还没有提供稳定ABI的保证。在ABI不稳定的情况下,库通常无法保证ABI的兼容性。这也是为什么Rust经常以源代码的形式分发,所有部分都需要从源代码重新编译的原因之一(ABI不稳定,直接分发binary可能会遇到兼容性问题)。
尽管没有给出保证,但这并不意味着每个版本都会造成破坏。
对于数据布局,Rust提供的保证并不多。其中一个原因是Rust允许编译器重排类型中的变量位置以寻求更小的结构大小。
在C这样的语言中,因为成员b要求A以位对齐,所以a、c之后都需要填充位的padding。
而Rust允许编译器调换a、b、c在内存中的位置,这样可以得到更紧凑的结构。具体介绍可以参考相关文档。
除此之外,还有一个典型的原因是Rust允许大小为0的类型,以及niche optimization。比如Option大于占用的大小和一个NonNull类型是相同的。利用NonNull中的Null值代表了不存在的情况。
给大家展示一个常见类型布局图:
为了与C互操作,对于Rust来说,引入了一个#[repr(C)]的标志。这个标志告诉Rust编译器,用C的布局方式来布局这个类型。对于有这些标记的类型,它们的ABI是稳定的,并且与C ABI规定的一致。
Rust对于layout能给出的保证都在这个页面里面。其他的真的就没有办法保证了。
Rust中允许很多同名函数,翻译成binary的时候也需要进行名字修饰。当前的修饰方式是编译器实现细节,没有给出过任何保证,部分采用了和C++ Itanium ABI相似的策略,部分采用了哈希后缀。
Rust RFC 试图给出一个稳定的命名修饰方案,目前未默认打开。
目前不应对Rust的命名修饰做出任何假设。
Rust中动态派发的方法是trait。方法依照trait组织在了一起。
对于这样的情况,Rust编译器会为impl Hello的类型生成一个虚表。对于object safe的trait,可以把一个trait想象成一个虚表。虚表的布局目前还没有保证,但不妨碍我们看看现在的实现。
第0个指针放Destructor,后面跟着字节放size和align。再后面放具体的函数指针。
可以看到Rust为foo生成的LLVM IR(target x-)。
函数入参a.0和a.1分别就是"对象的地址"和"虚表的地址"。可以看到虚表指针a.1用了readonly来修饰。
_ZNplayground3foohaee3acfccE就是被修饰过后的playground::foo的名字。
这3行是
后面3行也是类似
对于一个稳定的ABI而言,虚表的布局也需要稳定。
可以想象,破坏ABI兼容性有多么容易。当我们改变一下trait里面两个方法的顺序时,就会改变虚表的布局。之前编译的binary就不能用了,而从源代码编译则完全不受影响。
Rust中有panic和unwind机制。对于Rust ABI稳定来说,它们也是需要被稳定的一部分。目前人们在panic与外部语言交互的方式上进行努力。
默认是extern "Rust",也可以用extern "C"来标记某些函数需要按照C语言调用约定来。
Rust没有稳定的ABI,稳定ABI的目标主要通过C部分来实现。有一个库abi_stable就试图做这件事情,它把Rust类型变成ABI稳定的Rust类型,再跨二进制传递。
原则上来说,不应该跨二进制传递任何repr(Rust)的类型,因为没有办法保证其ABI兼容性。而绝大多数Rust库的作者也没有/也不会把ABI兼容性放在首要考虑的目标。
有趣的是,因为C++的ABI已经稳定了,所以我们可以在外部模拟(猜测)C++对象的布局。这个cxx库就做了这个。
将Rust ABI稳定化的新实验已经开始了。crABI就在试图稳定化Rust ABI,但距离真正稳定还有很长一段路要走,不过至少有人开始了努力。