首页/新闻资讯/正文详情

KAIST CS109 编程实践教程(三)

发布时间:2026/9/26 20:56:28 来源:云帆数科 栏目:资讯中心
KAIST CS109 编程实践教程(三)
setLineWidth(width: Double)设置轮廓绘制的笔宽度drawRectangle(x: Double, y: Double, width: Double, height: Double, s: DrawStyle) 绘制矩形drawCircle(x: Double, y: Double, radius: Double, s: DrawStyle) 在 ((x,y)) 处以半径 (r) 绘制一个圆setFont(size: Double, face: String) 设置文本绘制操作的字体参见上面的示例;drawText(text: String, x: Double, y: Double, a: TextAlign) 在位置 ((x, y)) 绘制对齐的字符串;done() 在完成绘制时建议调用此方法。更复杂的形状要绘制除了矩形和圆之外的形状您需要使用 ImageCanvas 的 shape 方法描述形状时沿着轮廓走。首先调用 beginShape()然后调用 moveTo(x, y) 前往轮廓的起点。现在通过一系列的 lineTo(x, y) 调用来描述形状的边界。您可以通过调用 closePath() 来完成轮廓这将返回到起点您在调用 moveTo(x, y) 时设置的位置。对于填充形状通常要调用 closePath对于轮廓描边形状这取决于您是否希望该形状是封闭曲线。最后调用 drawShape 来绘制形状。变换您可以修改坐标系统以便更容易地指定您的对象translate(x: Double, y: Double) 使点 ((x, y)) 成为新坐标系的原点;rotate(degrees: Double) 顺时针旋转坐标系;scale(sx: Double, sy: Double) 缩放 (x) 和 (y) 方向的坐标系统因此调用 scale(2.0, 2.0) 会使您的绘图尺寸加倍。通常您只想临时修改坐标系并在完成绘图的某个部分时返回到原始坐标系请参阅上面代码中的四边形。通过在更改坐标系之前调用 save()并在想要返回到先前设置时调用 restore() 来实现这一点。透明度通常后绘制的形状会覆盖先前绘制的形状计算机图形学中的“画家模型”。但是您可以调用 setAlpha(alpha) 来设置未来绘制操作的透明度。当 alpha 255 时绘图是不透明的并完全覆盖以前绘制的内容。当 alpha 128 时您以 50% 透明度进行绘制结果是原始颜色的一半与新绘制颜色的一半的混合。测量文本方法 textWidth(text: String) 返回在当前变换和字体设置下绘制文本的宽度。CS109UI 模块我编写了一个简单的模块叫做 cs109ui它使得可以编写具有简单图形用户界面的程序而无需了解 Swing 库或担心基于事件的编程。我们在CS109中的几个项目中使用这个模块。基本用法要使用该模块你需要按照 installation page 中的说明进行安装。该模块创建一个窗口。你可以通过绘制图像使用这里解释的操作来填充这个窗口然后调用 show。setTitle 命令设置窗口的标题。这是一个基本示例uitest1.kt。函数 draw 绘制到一个 java.awt.image.BufferedImage与 drawing example 中的绘图代码完全相同。import org.otfried.cs109ui.* import org.otfried.cs109ui.ImageCanvas import org.otfried.cs109.Color import org.otfried.cs109.DrawStyle import java.awt.image.BufferedImage fun draw(image: BufferedImage) { // get ImageCanvas for the image val g ImageCanvas(image) // clear background g.clear(Color.WHITE) // draw two filled circles g.setColor(Color.RED) g.drawCircle(50.0, 50.0, 20.0) // FILL is the default g.setColor(Color.ORANGE) g.drawCircle(250.0, 400.0, 20.0) // draw an unfilled circle with a pen of width 3 g.setColor(Color.MAGENTA) g.setLineWidth(3.0) g.drawCircle(415.0, 50.0, 15.0, DrawStyle.STROKE) // draw a filled and an unfilled Rectangle g.setColor(Color.CYAN) g.drawRectangle(20.0, 400.0, 50.0, 20.0, DrawStyle.FILL) g.drawRectangle(400.0, 400.0, 50.0, 20.0, DrawStyle.STROKE) // draw a line g.setLineWidth(1.0) // reset to default g.setColor(Color(0, 0, 255)) // same as Color.BLUE g.beginShape() g.moveTo(50.0, 50.0) g.lineTo(250.0, 400.0) g.drawShape(DrawStyle.STROKE) // draw a non-convex quadrilateral: g.save() // save current coordinate system g.translate(360.0, 260.0) // move origin to here g.rotate(-30.0) // rotate 30 degrees counter-clockwise g.beginShape() g.moveTo(0.0, 0.0) g.lineTo(30.0, -40.0) g.lineTo(60.0, 0.0) g.lineTo(30.0, -100.0) g.closePath() g.drawShape() g.restore() // restore current coordinate system // draw some text g.setColor(Color(0, 128, 0)) // a darker green g.setFont(20.0, Batang) g.drawText(Hello World!, 155.0, 225.0) g.drawText(안녕 하세요, 175.0, 245.0) // done with drawing g.done() } fun main(args: ArrayString) { setTitle(CS109 UI Test #1) val image BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB) draw(image) show(image) }我们编译并运行程序$ ktc uitest1.kt $ kt Uitest1Kt程序会打开一个像这样的新窗口https://github.com/OpenDocCN/cs-notes-pt3-zh/raw/master/docs/kaist-cs109-prog-prac/img/670ee8e22b35961a1f0a52eb01dc4370.jpg请注意尽管主函数已经返回程序尚未终止。要结束程序你必须手动使用鼠标关闭窗口。更新显示你可以通过绘制一个新图像并再次调用 show 来更改窗口的内容。你可以绘制到之前的相同图像或使用新图像。在窗口变化之间等待一段时间你可以执行一些简单的动画比如让对象在窗口内闪烁或移动。这里有一个简单的示例展示了一个闪烁的正方形。首先正方形以红色出现一秒钟然后以蓝色出现一秒钟。五秒后程序会自动终止uitest2.ktimport org.otfried.cs109ui.* import org.otfried.cs109ui.ImageCanvas import org.otfried.cs109.Color import org.otfried.cs109.DrawStyle import java.awt.image.BufferedImage fun draw(image: BufferedImage, color: Color) { val g ImageCanvas(image) g.clear(Color.WHITE) g.setColor(color) g.drawRectangle(100.0, 100.0, 300.0, 300.0) g.done() } fun showWait(image: BufferedImage, color: Color, ms: Int) { draw(image, color) // draw rectangle show(image) waitForMs(ms) // wait ms milliseconds } fun main(args: ArrayString) { setTitle(CS109 UI Blinking Rectangle) val image BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB) showWait(image, Color.WHITE, 500) // 0.5 sec white picture showWait(image, Color.RED, 1000) // 1 sec red rectangle showWait(image, Color.WHITE, 500) // 0.5 sec white picture showWait(image, Color.BLUE, 1000) // 1 sec blue rectangle showWait(image, Color.WHITE, 5000) // 5 secs white picture close() // close window and terminate program }同样你可以使用以下命令运行$ ktc uitest2.kt $ kt Uitest2Kt现在你可以编写有趣的程序比如Simon project你可以使用终端进行文本输出和文本输入使用窗口进行图形输出。动画通过快速更新窗口我们可以编写一些简单的平滑动画。这里有一个示例让一个红色球在屏幕上平滑移动uitest-animation.ktimport org.otfried.cs109ui.* import org.otfried.cs109ui.ImageCanvas import org.otfried.cs109.Color import org.otfried.cs109.DrawStyle import java.awt.image.BufferedImage fun draw(image: BufferedImage, x: Double, y: Double) { val g ImageCanvas(image) g.clear(Color.WHITE) g.setColor(Color.RED) g.drawCircle(x, y, 40.0) g.done() } fun main(args: ArrayString) { setTitle(CS109 UI Animation test) val image BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB) var x 30.0 var y 30.0 while (x 500.0) { draw(image, x, y) x 2 y 1 show(image) waitForMs(10) } }键盘输入如果我们想要更进一步我们可以通过窗口与用户进行所有交互。我们可以使用 drawString 函数在窗口中显示文本。下一步是允许用户通过在窗口中按键来控制程序。这是使用 waitKey 函数完成的。它会等待用户按下一个键然后返回所按下的字符。这里有一个简单的测试程序uitest3.ktimport org.otfried.cs109ui.* import org.otfried.cs109ui.ImageCanvas import org.otfried.cs109.Color import org.otfried.cs109.DrawStyle import java.awt.image.BufferedImage fun draw(image: BufferedImage, color: Color) { val g ImageCanvas(image) g.clear(Color.WHITE) g.setColor(color) g.drawRectangle(100.0, 100.0, 300.0, 300.0) g.done() } fun main(args: ArrayString) { setTitle(CS109 UI Keyboard Input Test) val image BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB) draw(image, Color.RED) show(image) println(Now press some keys inside the CS109 UI windows) println(Pressing q will terminate the program) while (true) { val ch waitKey() println(Got character $ch) if (ch q) close() // close window and terminate program } }窗口出现后尝试在窗口上聚焦时键入键。您应该在终端上看到消息“Got character”。按下“q”键将终止程序。对话框我们可以通过使用额外的弹出窗口通常称为“对话框”使我们的程序更加专业。最简单的方法只是向用户显示一条消息。用户必须按下“确定”才能继续程序。例如使用这段代码showMessage(This is a message)我们将得到这个弹出窗口https://github.com/OpenDocCN/cs-notes-pt3-zh/raw/master/docs/kaist-cs109-prog-prac/img/453fea90b7ab9f6f3881b6d6d7f3e08c.jpg稍微有趣的是我们可以询问一个是/否问题用户可以通过按下两个按钮中的一个来决定val yesno: Boolean askYesNo(Do you like this?)它看起来像这样https://github.com/OpenDocCN/cs-notes-pt3-zh/raw/master/docs/kaist-cs109-prog-prac/img/e3a3598d89fa3a7ed69e338b5ba99108.jpgaskYesNo 函数将用户的选择作为布尔值返回。最后我们可以要求用户输入一个字符串val name: String inputString(What is your name?)它看起来像这样https://github.com/OpenDocCN/cs-notes-pt3-zh/raw/master/docs/kaist-cs109-prog-prac/img/a7a4104c2748836445daaaeca60213b5.jpg再次该函数返回用户输入的字符串。如果用户按下“取消”或关闭弹出窗口则返回空字符串。高级功能在模块中还有一些更多的可能性从窗口接收鼠标按钮点击另外两个对话框以及设置用户输入的超时。当这些对项目有需要时我会记录这些内容但你也可以随时查看示例代码。编译成 JavaScript 并在浏览器中运行Kotlin 自带一个编译器将 Kotlin 源代码编译成 JavaScript准备好包含在网页中。因此你可以创建完全在 Web 浏览器中运行的应用程序。为了帮助你入门这里有一些提示和一个示例项目。我们首先创建一个新目录。我们将在此目录中创建三个文件canvas.html浏览器加载的网页canvas.js从网页加载的 JavaScript 代码jscanvas.js我们将使用的 org.otfried.cs109js.JsCanvas 类的 JavaScript 代码kotlin.jsJavaScript 的 Kotlin 标准库。让我们从最后一个开始kotlin.js 包含在 Kotlin 编译器附带的 kotlin-jslib.jar 文件中。用你喜欢的工具提取 kotlin.js 并将其放在你的新目录中jar 文件只是被简单压缩的存档。文件 jscanvas.js 也很容易获得它包含在你之前安装过的档案 cs109-jslib.jar 中。这是一个示例 HTML 文件canvas.htmlhtml head meta charsetutf-8 script srckotlin.js/script script srcjscanvas.js/script script srccanvas.js/script /head body onloadjavascript:Kotlin.modules[canvas].canvas.start(); canvas width600 height300 idcanvas/canvas div idtextThis is a fun paragraph. /div /body /html在文档的头部我们加载两个库和我们自己的 JavaScript 代码 canvas.js我们仍然需要生成。在 body 中我们包含两个元素一个 HTML 画布这是一个我们可以从 JavaScript 自由绘制的矩形区域和一个文本分区稍后我们可以从 JavaScript 中更新。现在从你的浏览器加载此文件你应该看到一个空白的白色矩形和下面的文本。此时我们应该在 Web 浏览器中打开 JavaScript 控制台。这是 JavaScript 的所有输出以及任何错误消息将会显示的地方。在 Firefox 中使用菜单、开发者、Web 控制台。在 Safari 中转到设置并勾选“显示开发菜单”复选框然后转到新出现的开发菜单并打开控制台。到目前为止控制台应该只显示一个错误消息TypeError: Kotlin.modules.canvas is undefined这是 body 标签中 onload 属性的响应。在这里我们指示 JavaScript 在网页完全加载后这一点很重要因为我们希望所有 HTML 元素在代码运行时都存在在 canvas.js 脚本中执行包 canvas 中的函数 start。剩下的是编写这个 start 函数并生成 canvas.js。这里是一个第一个示例canvas1.ktpackage canvas import org.otfried.cs109js.JsCanvas import org.otfried.cs109.Color import kotlin.browser.document import org.w3c.dom.* fun start() { println(Hello World from Javascript) val canvas JsCanvas(canvas) canvas.clear(Color.GREEN) val text document.getElementById(text) text?.appendChild(document.createTextNode(Was du hier liest ist kein Gedicht.)) }我们需要通过以下方式将该文件编译成 JavaScript$ kotlinc-js -output canvas.js canvas1.ktkotlinc-js 是 Kotlin 到 JavaScript 的编译器。我指定输出文件名在从 JavaScript 调用时对应于模块 Kotlin.modules[‘canvas’]。开始处的包声明将 start 函数放在 canvas 包中因此需要从 JavaScript 中调用它作为Kotlin.modules[canvas].canvas.start();这正是我们在 onload 属性中编写的内容。现在重新加载网页画布矩形会变成绿色底部的文本也会改变。在 JavaScript 控制台中你应该会看到 println 语句的输出。让我们通过添加一些颜色、文本和透明度来使我们的绘图更加有趣canvas2.ktpackage canvas import org.otfried.cs109js.JsCanvas import org.otfried.cs109.Color object Controller { val canvas JsCanvas(canvas) var x 30.0 var y 50.0 var alpha 45.0 fun draw() { canvas.clear(Color.WHITE) canvas.setAlpha(48) canvas.setColor(Color.GREEN) canvas.drawRectangle(10.0, 10.0, 100.0, 100.0) canvas.setAlpha(255) // opaque for (i in 0 .. 5) { for (j in 0 .. 5) { canvas.setColor(Color(Math.floor(255-42.5*i), Math.floor(255-42.5*j), 0)) canvas.drawRectangle(150.0 j*25.0, i*25.0, 25.0, 25.0) } } canvas.translate(x, y) canvas.setAlpha(128) canvas.rotate(alpha) canvas.setColor(Color.RED) canvas.setFont(32.0) canvas.drawText(Lovely, 0.0, 0.0) } } fun start() { println(Canvas2 starting...) Controller.draw() }我们再次编译$ kotlinc-js -output canvas.js canvas2.kt现在重新加载网页画布应该包含一个透明的绿色正方形在上面有一些半透明的红色文本右侧还有一个漂亮的颜色图案。到目前为止都很顺利现在让我们添加一些交互性。当你在画布上点击鼠标时文本应该移动到这个位置。按下键盘上的 ‘a’、‘s’、‘w’ 和 ‘z’ 键可以用来移动文本按下 ‘j’ 和 ‘k’ 键可以旋转它canvas3.ktpackage canvas import org.otfried.cs109js.JsCanvas import org.otfried.cs109.Color import kotlin.browser.window import org.w3c.dom.events.* object Controller { val canvas JsCanvas(canvas) var x 30.0 var y 50.0 var alpha 45.0 fun draw() { canvas.save() canvas.clear(Color.WHITE) canvas.setAlpha(48) canvas.setColor(Color.GREEN) canvas.drawRectangle(10.0, 10.0, 100.0, 100.0) canvas.setAlpha(255) // opaque for (i in 0 .. 5) { for (j in 0 .. 5) { canvas.setColor(Color(Math.floor(255-42.5*i), Math.floor(255-42.5*j), 0)) canvas.drawRectangle(150.0 j*25.0, i*25.0, 25.0, 25.0) } } canvas.translate(x, y) canvas.setAlpha(128) canvas.rotate(alpha) canvas.setColor(Color.RED) canvas.setFont(32.0) canvas.drawText(Lovely, 0.0, 0.0) canvas.restore() } fun keyDown(e: Event) { val ek e as KeyboardEvent var k ek.key if (k undefined) k ${ek.keyCode.toChar().toLowerCase()} when (k) { a - x - 3 s - x 3 w - y - 3 z - y 3 j - alpha 10.0 k - alpha - 10.0 else - return } draw() e.preventDefault() } fun mouseDown(e: Event) { val em e as MouseEvent x em.offsetX y em.offsetY draw() } } fun start() { println(Canvas3 starting...) println(Active keys are aswzjk) Controller.draw() window.addEventListener(keydown, { Controller.keyDown(it) }, true) window.addEventListener(mousedown, { Controller.mouseDown(it) }, true) }我们再次编译$ kotlinc-js -output canvas.js canvas3.kt重新加载网页。现在你应该能够点击画布并看到文本移动到这个位置。当你按下其中一个活动键时文本应该移动和旋转。最后让我们给我们的绘图添加一些动画效果。按下 ‘g’ 键开始动画并再次暂停。现在的代码还会调整画布大小以填满整个浏览器窗口只留下一点空间给滚动条和底部的文本canvas4.ktpackage canvas import org.otfried.cs109js.JsCanvas import org.otfried.cs109.Color import kotlin.browser.window import org.w3c.dom.events.* object Controller { val canvas JsCanvas(canvas) // change canvas size to fill entire browser window init { canvas.canvas.width window.innerWidth.toInt() - 20 canvas.canvas.height window.innerHeight.toInt() - 50 } var x 30.0 var y 50.0 var alpha 45.0 var animate false var timeStamp 0.0 fun draw() { canvas.save() canvas.clear(Color.WHITE) canvas.setAlpha(48) canvas.setColor(Color.GREEN) canvas.drawRectangle(10.0, 10.0, 100.0, 100.0) canvas.setAlpha(255) // opaque for (i in 0 .. 5) { for (j in 0 .. 5) { canvas.setColor(Color(Math.floor(255-42.5*i), Math.floor(255-42.5*j), 0)) canvas.drawRectangle(150.0 j*25.0, i*25.0, 25.0, 25.0) } } canvas.translate(x, y) canvas.setAlpha(128) canvas.rotate(alpha) canvas.setColor(Color.RED) canvas.setFont(32.0) canvas.drawText(Lovely, 0.0, 0.0) canvas.restore() if (animate) window.requestAnimationFrame { animate(it) } } fun animate(s: Double) { val delta s - timeStamp timeStamp s x delta / 2.0 if (x canvas.width) x 0.0 alpha 0.3 * delta if (alpha 360.0) alpha 0.0 draw() } fun keyDown(e: Event) { val ek e as KeyboardEvent var k ek.key if (k undefined) k ${ek.keyCode.toChar().toLowerCase()} when (k) { a - x - 3 s - x 3 w - y - 3 z - y 3 j - alpha 10.0 k - alpha - 10.0 g - { if (!animate) timeStamp window.performance.now() animate !animate } else - return } draw() e.preventDefault() } fun mouseDown(e: Event) { val em e as MouseEvent x em.offsetX y em.offsetY draw() } } fun start() { println(Canvas3 starting...) println(Active keys are aswzjk and g for animation) Controller.draw() window.addEventListener(keydown, { Controller.keyDown(it) }, true) window.addEventListener(mousedown, { Controller.mouseDown(it) }, true) }现在你可以编写自己的 web 应用程序了。或者尝试一下 我的实现 的 2048 游戏。移动键是 ‘u’、‘d’、‘l’ 和 ‘r’。直接使用 Javascript Canvas API我的 JsCanvas 类很方便因为你可以使用相同的绘图代码来绘制位图和 CS109 Android 框架当然你也可以从 HTML 文件中移除 jscanvas.js 文件并直接使用 JavaScript 函数来绘制到画布上。查看 canvas-nojscanvas.kt 可以看到没有 JsCanvas 的最新版本是什么样子的。你可能会发现 Mozilla 文档 有所帮助虽然它是为 JavaScript 设计的但其中很多代码在 Kotlin 中也可以不变地使用。Android 迷你应用框架Android 软件开发工具包非常复杂超出了本教程的范围。相反我们将看到如何仅使用我们迄今学到的工具使用“KAIST CS109 迷你应用框架”为 Android 编写基于画布的应用程序。第一个示例绘图轻点、双击和轻扫对话框定时器和动画菜单使用手机传感器参考资料Kotlin 文档在线尝试 Kotlin《Kotlin 实战》目前是唯一一本关于 Kotlin 的书甚至还没有完成。这是一本好书但假定读者已经了解 Java。Java 库参考文档本文档使用 Java 语法和类型名称。如果有任何不理解的地方请在课程论坛上提问

相关推荐

数据中心机房设计全解:从功率密度到气流组织的落地指南
数据中心机房设计全解:从功率密度到气流组织的落地指南

简介:数据中心机房设计方案文档,面向机房建设相关的设计人员、系统集成商、项目经理及甲方技术负责人,是一份可直接参考的B级机房设计模板。方案依据《电子信息系统机房设计规范》《电子计算机场地通用规范》等标准编写,覆盖机房平… · 2026/9/26 20:56:22

PowerShell提供程序与PSDrive:把注册表、证书库当文件夹逛
PowerShell提供程序与PSDrive:把注册表、证书库当文件夹逛

PowerShell 系列写到第七篇,终于要聊一聊这个系列里最“Windows 味”的概念——提供程序(Provider)和驱动器(PSDrive)。说实话,很多人用了很久 PowerShell,天天敲cd C:\、dir,却不知… · 2026/9/26 20:56:22

智慧小区微信小程序全流程落地:功能设计与避坑实践
智慧小区微信小程序全流程落地:功能设计与避坑实践

这几年我一直在一线做智慧社区相关的项目,智慧小区微信小程序这块前前后后经手了七八个,从最初只做一个物业公告板,到后来把门禁通行、访客预约、物业缴费、报修工单、停车缴费、社区商城全塞进一个小程序里,踩过的坑和沉淀下来的… · 2026/9/26 20:56:22

开源AI编程本地部署实战:从模型选型到工具链配置全指南
开源AI编程本地部署实战:从模型选型到工具链配置全指南

两年多前,我第一次用AI写代码的时候,怎么也想不到这玩意儿会卷得这么厉害。Cursor火起来之后,几乎每个技术群都在聊AI编程;GitHub Copilot、Windsurf、Trae这些商业产品一个比一个猛,好像不开个会员就没法正常写代码了… · 2026/9/26 21:34:33

模拟退火算法在路径规划中的应用:原理、Python实现与GUI展示
模拟退火算法在路径规划中的应用:原理、Python实现与GUI展示

1. 从一次给客户排配送路线说起:路径规划问题到底难在哪几个月前,有个做同城配送的朋友找我帮忙,说手头有二十几个取送货点,每次靠人工排路线,司机跑出来的距离忽高忽低,客户催得紧的时候根本来不及细排。我… · 2026/9/26 21:34:26

SSM商品拍卖系统毕设全攻略:从需求分析到并发控制与答辩
SSM商品拍卖系统毕设全攻略:从需求分析到并发控制与答辩

1. 这个毕设题目为什么值得做:拍卖系统的定位与难点拆解先交代个背景。2026年的毕设季,很多同学会在选题阶段卡住很久。我的建议始终是那句老话:选一个"看起来简单、做起来有东西讲"的题目。商品拍卖系统恰好是这种矛盾体——功能边… · 2026/9/26 21:34:26

WorkBuddy + Flask + SQLite:日更个人站自动化建站实战
WorkBuddy + Flask + SQLite:日更个人站自动化建站实战

1. 为什么我选择 WorkBuddy Flask SQLite 这套组合先说结论:这套组合不是拍脑袋选的,是我在试过 WordPress、Shopify 和纯静态源码建站之后,针对“个人内容站 日更 完全掌控数据”这个具体场景,反复权衡下来的结果。WorkBuddy… · 2026/9/26 21:34:26

Oracle 21c Windows客户端安装配置与避坑指南
Oracle 21c Windows客户端安装配置与避坑指南

简介:这是一份面向Windows 32位环境的完整数据库客户端安装资源,对应甲骨文数据库21c客户端21.3版,适合需要在本机部署客户端以连接远程数据库的开发、运维及数据处理人员使用。压缩包共收录一千四百零三个文件,整体大小约八百六十… · 2026/9/26 21:34:26

网盘直链原理与实战:从HTTP协议到NAS挂载
网盘直链原理与实战:从HTTP协议到NAS挂载

1. 直链不是“魔法”,而是网盘服务协议与HTTP协议博弈的副产品 “网盘免客户端下载”这个说法,乍一听像在绕开平台规则——但事实恰恰相反:它不是钻空子,而是 把网盘本就公开提供的资源访问能力,从封闭的客户端界面里… · 2026/9/26 21:34:26

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码