分享通义ChatGPT实用技能123
ChatGPT 在编程方面的表现非常优秀,你可以向它请教各种各样的编程问题,甚至让它帮你写代码,成功的关键取决于你的prompt是否写得合适。「通义灵码 · 体验 AI 编码,开 AI 盲盒」
前言
作为一名程序员,你一定有过这样的经历:排查某个 bug 花费了好几个小时,在各个搜索引擎尝试搜索,浏览了几十甚至上百个网站,结果搜到的答案千篇一律,没有一个说到点上。而自从有了 ChatGPT,就可以告别这种窘境,不需要到各个网站搜索答案,也不用在各种技术交流群里“低三下四”地求人。
ChatGPT 在编程方面的表现非常优秀,你可以向它请教各种各样的编程问题,甚至让它帮你写代码,成功的关键取决于你的 prompt 是否写得合适。
假如给 ChatGPT 设定一个角色——软件开发专家,那么它将会如何帮助我们编程,以下我们就来看看 ChatGPT 在软件开发中的实际应用。
输入 prompt:
假如给 ChatGPT 设定一个角色——软件开发专家,那么它将会如何帮助我们编程?
ChatGPT 输出:
作为软件开发专家,ChatGPT 可以为编程工作提供多方面的帮助,以下是一些具体表现:
代码编写与实时续写:当开发者阐述需求或描述功能时,ChatGPT 能够理解自然语言并生成对应的代码片段,无论是简单函数还是复杂业务逻辑。它还可以根据现有代码进行行级实时续写,协助完成程序编写。
问题解答与技术咨询:对于编程中遇到的具体技术问题、概念疑惑或者最佳实践,ChatGPT 能快速给出详尽的答案和解释,指导开发者解决难题。
设计与架构建议:在系统设计阶段,ChatGPT 可以根据项目需求和场景特点,为开发者提供合理的设计模式、架构方案以及模块划分建议。
代码审查与优化:对已有的代码段,ChatGPT 可以分析其潜在的问题,并提出性能优化、可读性改进等方面的建议。
单元测试生成:基于给定的代码逻辑,ChatGPT 能自动生成相应的单元测试用例,确保代码质量及正确性。
文档撰写与注释生成:结合代码实现,ChatGPT 可以为项目生成详细的技术文档,包括API接口说明、类库使用指南等;同时,也能自动生成规范的代码注释,提高代码可维护性。
异常排查与调试辅助:面对运行时错误或异常情况,ChatGPT 可以通过分析日志信息、报错堆栈,为开发者提供可能的故障原因分析和调试思路。
总结来说,具备软件开发专家角色的 ChatGPT 将成为程序员的强大工具和智能助手,在整个开发生命周期内提供全面的支持。
角色已经设置好了,下面看看它的表现如何。
一、生成代码
ChatGPT 在生成代码方面非常强大,甚至跟专业程序员不相上下。我们以 java语言为例小试牛刀。
输入prompt:
请帮我生成JAVA反射函数示例代码并执行结果分析。
ChatGPT输出:
在Java中,反射机制允许我们在运行时分析类和对象的信息,并动态调用类的方法或访问字段。以下是一个简单的Java反射函数示例代码及其执行结果分析:
import java.lang.reflect.Method; public class ReflectionExample { private String secretValue = "This is a secret message"; public void displayMessage(String message) { System.out.println("Displaying message: " + message); } // 获取并执行私有方法 public static void main(String[] args) throws Exception { ReflectionExample example = new ReflectionExample(); // 获取Class对象 Class<?> clazz = example.getClass(); // 获取私有字段并设置值 Field secretField = clazz.getDeclaredField("secretValue"); secretField.setAccessible(true); // 打破封装,允许访问私有字段 System.out.println("Original secret value: " + secretField.get(example)); secretField.set(example, "New secret message"); System.out.println("Updated secret value: " + secretField.get(example)); // 获取公共方法并执行 Method displayMethod = clazz.getMethod("displayMessage", String.class); displayMethod.invoke(example, "Invoked through reflection"); // 获取并执行私有构造器(假设存在) Constructor<ReflectionExample> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); ReflectionExample anotherExample = constructor.newInstance(); System.out.println("Created an instance of ReflectionExample using the private constructor."); } }
执行结果分析:
首先,我们通过example.getClass()获取到ReflectionExample类的Class对象。
接着,使用getDeclaredField方法获取名为secretValue的私有字段,并通过setAccessible(true)使得能够访问私有属性。然后打印出原始值,再修改其值并再次打印以验证更新成功。
使用getMethod方法找到displayMessage公共方法,并通过invoke方法来动态调用该方法,传入参数"Invoked through reflection",此时控制台会输出相应的消息。
最后,利用getDeclaredConstructor方法获取无参构造器(即使它是私有的),同样通过setAccessible(true)解除对私有构造器的访问限制,并创建一个新的ReflectionExample实例。
这个示例展示了如何利用Java反射机制来访问私有字段、调用公有和私有方法以及构造对象。然而,在实际开发中,过度依赖反射可能会影响程序性能和可读性,应谨慎使用。
输入prompt:
使用ChatGPT创建一个2048游戏
ChatGPT输出:
创建一个2048游戏的最小完整实现需要HTML、CSS和JavaScript。以下是一个简单的实现,你可以将这些代码复制到本地文件中,比如命名为2048.html,然后用浏览器打开这个文件来玩游戏。
<html> <head> <title>2048 Game</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 0; } .container { width: 480px; position: relative; } .grid-container { display: grid; grid-template-columns: repeat(4, 100px); grid-gap: 15px; background-color: #bbada0; padding: 15px; border-radius: 10px; position: relative; } .tile { width: 100px; height: 100px; background: #cdc1b4; border-radius: 3px; display: flex; justify-content: center; align-items: center; font-size: 30px; font-weight: bold; color: #776e65; } .tile-2 { background: #eee4da; } .tile-4 { background: #ede0c8; } .tile-8 { background: #f2b179; color: #f9f6f2; } /* Additional tile styles for 16, 32, 64, etc. go here */ .game-message { width: 500px; text-align: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: none; } .game-message p { font-size: 36px; font-weight: bold; color: #776e65; } .game-message .button { background: #8f7a66; color: #f9f6f2; border: none; padding: 10px 20px; font-size: 18px; cursor: pointer; margin-top: 20px; } .game-message a { color: inherit; text-decoration: none; } </style> </head> <body> <div class="container"> <div class="grid-container" id="grid-container"> <!-- Tiles will be generated here --> </div> <div class="game-message" id="game-message"> <p>Game Over!</p> <button class="button" onclick="setup()">Try again</button> </div> </div> <script> // Logic for the 2048 game var grid, score, gameOver; function setup() { grid = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]; score = 0; gameOver = false; addNumber(); addNumber(); updateView(); document.getElementById('game-message').style.display = 'none'; } function addNumber() { var options = []; for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { if (grid[i][j] === 0) { options.push({ x: i, y: j }); } } } if (options.length > 0) { var spot = options[Math.floor(Math.random() * options.length)]; var randomNumber = Math.random() > 0.5 ? 2 : 4; grid[spot.x][spot.y] = randomNumber; } } function updateView() { var container = document.getElementById('grid-container'); container.innerHTML = ''; for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { var tile = document.createElement('div'); tile.classList.add('tile'); var value = grid[i][j]; if (value > 0) { tile.textContent = value; tile.classList.add('tile-' + value); } container.appendChild(tile); } } } function copyGrid(grid) { var extra = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]; for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { extra[i][j] = grid[i][j]; } } return extra; } function compare(a, b) { for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { if (a[i][j] !== b[i][j]) { return true; } } } return false; } function slide(row) { var arr = row.filter(val => val); var missing = 4 - arr.length; var zeros = Array(missing).fill(0); arr = zeros.concat(arr); return arr; } function combine(row) { for (var i = 3; i >= 1; i--) { var a = row[i]; var b = row[i - 1]; if (a == b) { row[i] = a + b; score += row[i]; row[i - 1] = 0; } } return row; } function operate(row) { row = slide(row); row = combine(row); row = slide(row); return row; } function flipGrid(grid) { for (var i = 0; i < 4; i++) { grid[i].reverse(); } return grid; } function rotateGrid(grid) { var newGrid = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]; for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { newGrid[i][j] = grid[j][i]; } } return newGrid; } function isGameOver() { for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { if (grid[i][j] == 0) { return false; } if (j !== 3 && grid[i][j] === grid[i][j + 1]) { return false; } if (i !== 3 && grid[i][j] === grid[i + 1][j]) { return false; } } } return true; } function checkGameOver() { if (isGameOver()) { document.getElementById('game-message').style.display = 'block'; gameOver = true; } } function keyPressed(event) { if (gameOver) { return; } var flipped = false; var rotated = false; var played = true; switch(event.keyCode) { case 39: // Right // No action needed break; case 40: // Down grid = rotateGrid(grid); rotated = true; break; case 37: // Left grid = flipGrid(grid); flipped = true; break; case 38: // Up grid = rotateGrid(grid); rotated = true; flipped = true; break; default: played = false; } if (played) { var past = copyGrid(grid); for (var i = 0; i < 4; i++) { grid[i] = operate(grid[i]); } var changed = compare(past, grid); if (flipped) { grid = flipGrid(grid); } if (rotated) { grid = rotateGrid(grid); grid = rotateGrid(grid); grid = rotateGrid(grid); } if (changed) { addNumber(); } updateView(); checkGameOver(); } } document.addEventListener('keydown', keyPressed); // Variables to track touch start positions var touchStartX = null; var touchStartY = null; // Event listener for touch start document.addEventListener('touchstart', function(event) { if (event.touches.length > 1) return; // Only single touch events touchStartX = event.touches[0].clientX; touchStartY = event.touches[0].clientY; event.preventDefault(); // Prevent scrolling when inside DIV }, { passive: false }); // Event listener for touch move document.addEventListener('touchmove', function(event) { event.preventDefault(); // Prevent scrolling when inside DIV }, { passive: false }); // Event listener for touch end document.addEventListener('touchend', function(event) { if (!touchStartX || !touchStartY || gameOver) return; var deltaX = event.changedTouches[0].clientX - touchStartX; var deltaY = event.changedTouches[0].clientY - touchStartY; // Determine swipe direction if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontal swipe if (deltaX > 0) { moveRight(); } else { moveLeft(); } } else { // Vertical swipe if (deltaY > 0) { moveDown(); } else { moveUp(); } } touchStartX = null; touchStartY = null; }); // Move functions function moveLeft() { keyPressed({ keyCode: 37 }); } function moveUp() { keyPressed({ keyCode: 38 }); } function moveRight() { keyPressed({ keyCode: 39 }); } function moveDown() { keyPressed({ keyCode: 40 }); } setup(); </script> </body> </html>
输入prompt:
使用ChatGPT写八皇后算法解题思路及代码
ChatGPT输出:
解题思路:八皇后问题是在一个8x8的棋盘上放置8个皇后,使得任意两个皇后不在同一行、同一列或同一斜线上。解决这个问题通常采用回溯算法。
初始化:创建一个8x8的二维数组(也可以用一维数组模拟)表示棋盘,所有元素初始化为0,表示当前位置没有皇后。同时定义一个结果列表存储所有的解决方案。
递归函数设计:
- 对于棋盘的每一行,尝试在该行的所有列位置放置皇后。
- 在尝试放置时,检查当前位置是否与之前已经放置的皇后冲突,即检查当前列是否有皇后,以及左上和右上对角线上是否有皇后。
- 如果当前位置可以放置皇后,则在该位置标记放置,并进入下一行继续放置皇后。
- 当成功放置完第8个皇后(即处理到最后一行),说明找到了一种解决方案,将当前棋盘状态存入结果列表中。
- 若在某一行找不到合适的列放置皇后,或者放置完所有皇后后,需要回溯至上一行,取消掉上一行最后一个皇后的放置,然后继续在上一行尝试其他列。
- 结束条件:遍历完所有可能的情况后,输出结果列表中的所有解决方案。
以下是使用Python实现的简单代码:
def can_place(row, col, board): # 检查列是否有皇后 for i in range(row): if board[i] == col: return False # 检查左上和右上对角线是否有皇后 for i in range(row): if board[i] - i == col - row or board[i] + i == col + row: return False return True def place_queen(row, board, solutions): if row == n: solutions.append(board[:]) return for col in range(n): if can_place(row, col, board): board[row] = col place_queen(row + 1, board, solutions) # 回溯 board[row] = -1 solutions = [] board = [-1] * n place_queen(0, board, solutions) return [list(solution) for solution in solutions] # 测试代码 print(solveNQueens(8))
ChatGPT 不仅给出了代码,还提供了注释,并在末尾做了总结。这对于初级程序员或想要学习java、python等语言的小白来说,简直是大大的福利。
二、解释代码
如果想快速掌握一门编程语言,阅读并理解别人写的代码是一个不错的选择。然而,如果遇到不懂之处,就会很困扰。而有了 ChatGPT 之后,再遇到这种情况,只需将这部分代码发给它,让它来解释即可。
输入prompt:
请解释下面代码段的含义并预测执行结果:
package com.qcadoo.mes.basic; import java.util.List; import java.util.Map; import com.google.common.collect.Lists; public final class ProductList extends IntegrationJsonMessage { private List<Map<String, Object>> staff = Lists.newArrayList(); public ProductList(final List<Map<String, Object>> staffEntities) { staff = staffEntities; } }
ChatGPT输出:
这个代码段定义了一个名为ProductList的Java类,该类继承自IntegrationJsonMessage类。ProductList类主要用于表示一个包含员工信息的列表数据结构,并且使用了Google Guava库中的Lists.newArrayList()方法初始化成员变量。
代码解释:
package com.qcadoo.mes.basic; 定义了包名,表明此类位于com.qcadoo.mes.basic包下。
引入了java.util.List和java.util.Map两个接口,用于处理列表和映射(键值对)数据类型。
引入了com.google.common.collect.Lists,这是Google Guava库提供的工具类,提供了许多方便操作列表的方法。
public final class ProductList extends IntegrationJsonMessage { ... } 定义了一个公开的、不可被继承的ProductList类,它扩展自IntegrationJsonMessage类,可能意味着此类具备序列化/反序列化为JSON消息的能力。
类中有一个私有成员变量:private List<Map<String, Object>> staff = Lists.newArrayList();
这个成员变量是一个列表,其中每个元素都是一个映射对象(Map),映射的键是字符串类型,值是Object类型。初始时,staff被设置为一个新的空列表。
类包含一个构造函数:public ProductList(final List<Map<String, Object>> staffEntities) { staff = staffEntities; }
当创建ProductList对象时,可以通过此构造函数传入一个List<Map<String, Object>>类型的参数staffEntities。在构造函数内部,将传入的staffEntities赋值给类的成员变量staff,这样新创建的对象就会持有传入的员工实体列表。
执行结果预测: 由于这是一个类定义,本身不直接产生执行结果。当通过构造函数创建ProductList实例并传入一个员工实体列表时,该实例的staff属性将会存储传入的列表内容。但具体的执行结果取决于如何实例化和使用这个类。
ChatGPT 准确解释了这段代码的含义并计算了输出结果。由此看来,ChatGPT 在这方面的能力确实非常不错。
三、解释报错信息
程序执行时报错是很正常的一件事,根据报错信息,大多数时候可以确定问题,但有时候报错信息不够清晰,就很难定位问题,这会让开发人员产生极大的挫败感。ChatGPT 的出现让排查错误更加高效。只需将报错信息复制粘贴到 ChatGPT 中,它就会说明出错的原因和错误的含义并给出解决思路或方案,大大节省了我们排查错误的时间。示例如下。
输入prompt:
请解释一下这段报错日志是什么意思?
第一次未粘贴日志内容
如果您能提供一段Java报错日志,例如异常堆栈信息、错误消息等,我可以帮助您分析和解读它。通常,Java的错误日志会包含以下关键信息:
异常类型:这是抛出的异常类名,如NullPointerException、IOException等,可以帮助我们识别问题的大致类型。
异常消息:简短描述了发生异常的原因,可能包括文件路径不正确、空指针引用等详细情况。
堆栈跟踪(Stack Trace):从引发异常的方法开始,到最终捕获或未捕获异常的地方为止,一系列方法调用的过程,显示了代码执行路径以及在哪个位置抛出了异常。
请提供具体日志后我才能给出详细的解释。
第二次粘贴了日志内容
WAIT Compiling... 98% after emitting CopyPlugin ERROR Failed to compile with 1 error error in ./src/App.vue?vue&type=style&index=0&lang=scss&
Syntax Error: SassError: File to import not found or unreadable: F:\code\src\assets\css\element.scss. on line 136 of F:\code\src\App.vue
@import './assets/css/element.scss';
ChatGPT输出:
这段报错日志来自Vue.js项目在编译过程中出现的Sass编译错误。错误信息详细解释如下:
WAIT Compiling...: 这是Webpack或其他构建工具正在进行项目的编译过程,并显示了当前的编译进度。
98% after emitting CopyPlugin: 编译进程已经完成了大约98%,并且CopyWebpackPlugin插件已完成资源文件的复制工作(如果配置了的话)。
ERROR Failed to compile with 1 error: 表示编译过程中遇到一个错误并导致编译失败。
error in ./src/App.vue?vue&type=style&index=0&lang=scss&: 错误发生在App.vue组件的第0个内联样式部分,该样式部分采用SCSS(Sass的一种语法格式)编写。
Syntax Error: SassError: File to import not found or unreadable: 提供了一个具体的Sass错误,指出在编译过程中尝试导入一个文件时遇到了问题,文件未找到或者无法读取。
File to import not found or unreadable: F:\code\src\assets\css\element.scss: 指定的待导入文件路径为 F:\code\src\assets\css\element.scss,编译器未能在这个位置找到或正确读取到这个SCSS文件。
on line 136 of F:\code\src\App.vue: 错误发生的具体行号是在App.vue组件的第136行。
>> @import './assets/css/element.scss';: 显示出引发错误的代码行,即试图从相对路径./assets/css/element.scss导入样式文件。
综上所述,解决这个问题需要检查以下几点:
确保element.scss文件存在于指定的目录下:F:\code\src\assets\css\element.scss。
检查App.vue中引用此SCSS文件的相对路径是否正确无误,特别是在多层嵌套目录结构下的引用。
确认文件权限正常,编译工具能够访问和读取这个文件。
可以看到,ChatGPT 准确识别了这段报错信息并给出了解决思路。
四、编写测试脚本
测试是软件开发的重要环节之一,而编写有效的测试脚本往往很耗时且具有挑战性。ChatGPT 可以简化这一过程,帮助你创建高质量的测试脚本。你可以简单地用自然语言描述想创建的测试场景,指定测试数据和其他细节,ChatGPT 就能按要求自动生成测试脚本,帮助你节省大量时间,而且它提供的代码质量非常高。
输入prompt:
帮忙编写一个web系统接口的黑盒测试脚本
ChatGPT输出:
黑盒测试是一种只关注系统功能,不考虑内部结构和代码实现的测试方法。以下是一个基于HTTP协议、使用Python的requests库编写的简单Web接口黑盒测试脚本示例,假设我们要测试一个用户注册接口:
import requests import json # 定义测试用例数据 test_cases = [ { "username": "testuser1", "email": "testuser1@example.com", "password": "SecurePassword123!", "expected_status_code": 201, # 成功创建用户的HTTP状态码 }, { "username": "invalid_username", "email": "not_an_email", "password": "short", "expected_status_code": 400, # 预期错误的HTTP状态码(例如:参数错误) }, ] # 接口URL register_url = "http://example.com/api/register" # 执行测试用例 for case in test_cases: payload = { "username": case["username"], "email": case["email"], "password": case["password"], } # 发送POST请求 response = requests.post(register_url, data=json.dumps(payload), headers={"Content-Type": "application/json"}) # 检查响应状态码 assert response.status_code == case["expected_status_code"], f"Test case failed. Expected status code {case['expected_status_code']}, got {response.status_code}." # 如果预期是成功创建用户,还可以进一步检查返回的数据(如用户ID等) if case["expected_status_code"] == 201: user_data = response.json() # 根据实际情况添加更多断言 assert "id" in user_data, "Response does not contain expected 'id' field." # 清理工作(如删除刚创建的用户,仅在有相应权限时执行) if case["expected_status_code"] == 201 and hasattr(response, "user_id"): delete_url = f"http://example.com/api/users/{user_data['id']}" requests.delete(delete_url) print("All test cases passed.")
请注意,这个示例非常基础,实际应用中需要根据具体接口文档编写更详尽的测试用例,并且可能涉及到数据库交互后的清理工作、身份验证等问题。同时,在进行接口测试时,务必遵循API的设计规范和安全策略。
ChatGPT 很快生成了一个黑盒测试脚本并介绍了使用方法,非常人性化。
五、漏洞和风险分析
ChatGPT 还可以帮助开发人员预测代码的潜在风险,识别其中的安全漏洞,而不必先运行它,这可以让开发人员及早发现错误,提高代码质量。
输入prompt:
帮忙分析一下这段代码是否有问题
export function generateCodeFrame ( source: string, start: number = 0, end: number = source.length ): string { const lines = source.split(/\r?\n/) let count = 0 const res = [] for (let i = 0; i < lines.length; i++) { count += lines[i].length + 1 if (count >= start) { for (let j = i - range; j <= i + range || end > count; j++) { if (j < 0 || j >= lines.length) continue res.push(`${j + 1}${repeat(` `, 3 - String(j + 1).length)}| ${lines[j]}`) const lineLength = lines[j].length if (j === i) { // push underline const pad = start - (count - lineLength) + 1 const length = end > count ? lineLength - pad : end - start res.push(` | ` + repeat(` `, pad) + repeat(`^`, length)) } else if (j > i) { if (end > count) { const length = Math.min(end - count, lineLength) res.push(` | ` + repeat(`^`, length)) } count += lineLength + 1 } } break } } return res.join('\n') }
ChatGPT输出:
这段代码定义了一个名为 generateCodeFrame 的函数,其功能是从给定的源代码字符串中生成一个代码片段,并在指定的起始和结束位置(默认为整个字符串)添加行号和下划线高亮显示。这个函数主要用于错误定位或者代码展示。
分析如下:
函数接受三个参数:
source: 需要处理的源代码字符串。
start: 高亮开始的位置,默认为0,即从字符串开头。
end: 高亮结束的位置,默认为源代码字符串长度,即到字符串末尾。
将源代码按换行符拆分成数组 lines。
初始化变量 count 用于记录当前已遍历字符数,初始化结果数组 res 存储最终输出的内容。
遍历每一行(通过索引 i),累加字符长度并计数换行符。
当 count 大于等于 start 时,进入内层循环,该循环会处理以当前位置为中心的一个范围内的行(上下各 range 行,未给出 range 的具体值,假设是预设的一个常量)。如果超出数组边界,则跳过当前循环。
对于符合条件的每一行,将格式化后的行号、空格和行内容添加到结果数组 res 中。对于当前行(即 j === i),会在指定范围内添加下划线高亮。
内层循环结束后,跳出外层循环。
最后,将结果数组 res 拼接成单个字符串并返回。
潜在问题:
参数 range 在函数签名中没有声明或提供默认值,但被用在了内层循环条件里。这意味着调用此函数时需要额外传入 range 参数,否则会导致逻辑错误。
如果输入的 end 值小于 start,则不会产生任何高亮效果,这可能与预期不符。可以考虑增加对这种情况的处理,比如交换 start 和 end 的值。
总体而言,代码实现的功能清晰明了,但在实际使用前需要补充缺失的 range 参数,并根据实际情况完善对异常输入的处理。
我们输入了一段代码,ChatGPT 迅速找出了可能存在的漏洞并给出了修复方法。
六、重构建议
一个复杂的代码库可能包含难以理解或修改的代码。重构可以在不改变其外部行为的情况下改进代码的设计。ChatGPT 就是一个能提供重构建议的优秀工具,可以帮助我们写出可维护和可理解的代码。
例如,我们可以向 ChatGPT 咨询如何重构函数,提高其性能。ChatGPT 会分析我们提供的代码并给出修改建议,比如使用内置函数或者算法替换循环,同时删除多余的代码。ChatGPT 还可以用来改善代码的结构,使代码更容易理解和维护。当然,也可以用它来检测不良的代码,避免一些可维护性、可读性和可扩展性方面的问题。
输入prompt:
我提供一段代码,请你给出重构和优化建议
export function generateCodeFrame ( source: string, start: number = 0, end: number = source.length ): string { const lines = source.split(/\r?\n/) let count = 0 const res = [] for (let i = 0; i < lines.length; i++) { count += lines[i].length + 1 if (count >= start) { for (let j = i - range; j <= i + range || end > count; j++) { if (j < 0 || j >= lines.length) continue res.push(`${j + 1}${repeat(` `, 3 - String(j + 1).length)}| ${lines[j]}`) const lineLength = lines[j].length if (j === i) { // push underline const pad = start - (count - lineLength) + 1 const length = end > count ? lineLength - pad : end - start res.push(` | ` + repeat(` `, pad) + repeat(`^`, length)) } else if (j > i) { if (end > count) { const length = Math.min(end - count, lineLength) res.push(` | ` + repeat(`^`, length)) } count += lineLength + 1 } } break } } return res.join('\n') }
ChatGPT输出:
这段代码的功能是生成一个带有行号和高亮下划线的代码片段,用于错误提示或代码展示。在提供重构和优化建议之前,请注意缺失变量 range 的定义,它在内层循环中被使用。以下是一些重构和优化的建议:
明确范围参数:首先需要修复 range 变量的问题,确保其在函数签名中声明并提供默认值。export function generateCodeFrame( source: string, start: number = 0, end: number = source.length, range: number = 2 // 假设我们给 range 设定一个默认值 ): string {}
提取常量与重复计算:
将字符串模板和重复方法(如 repeat())的结果作为常量提取出来,避免重复计算。
如果 repeat() 是自定义的方法,可以考虑利用原生的字符串填充方法 .padStart() 或 .padEnd() 替代。const paddingSpace = ' '.repeat(3); const underlineChar = '^'.repeat(1); // ... res.push(`${j + 1}${paddingSpace.slice(String(j + 1).length)}| ${lines[j]}`);
简化条件判断:
外层循环可以提前退出,减少不必要的计算,当 count > end 时跳出循环。for (let i = 0; count <= end && i < lines.length; i++) { ... }
逻辑结构调整:
当 j > i 时,可以将 count += lineLength + 1 移到外层循环,避免每次内层循环都进行累加。for (let i = 0; count <= end && i < lines.length; i++) { count += lines[i].length + 1; if (count >= start) { ... } }
可读性改进:
使用更清晰的变量命名以增强代码可读性。
综合以上建议,优化后的代码可能如下所示:export function generateCodeFrame( source: string, start: number = 0, end: number = source.length, range: number = 2 ): string { const lines = source.split(/\r?\n/); let count = 0; const res = []; const paddingSpace = ' '.repeat(3); const underlineChar = '^'.repeat(1); for (let i = 0; count <= end && i < lines.length; i++) { count += lines[i].length + 1; if (count >= start) { for (let j = Math.max(0, i - range); j <= Math.min(i + range, lines.length - 1) || end > count; j++) { res.push(`${j + 1}${paddingSpace.slice(String(j + 1).length)}| ${lines[j]}`); if (j === i) { const pad = start - (count - lines[j].length) + 1; const length = Math.min(end - start, lines[j].length - pad); res.push(` |${paddingSpace}+${underlineChar.repeat(length)}`); } else if (j > i && end > count) { const length = Math.min(end - count, lines[j].length); res.push(` |${paddingSpace}${underlineChar.repeat(length)}`); } if (j < lines.length - 1) { count += lines[j].length + 1; } } break; } } return res.join('\n'); }
此外,根据具体需求和场景,还可以考虑其他优化措施,例如:
对于非常大的源代码文件,可以考虑只处理错误附近一定数量的行来提高性能。
若 repeat() 方法是自定义实现,确实应当替换为原生的字符串填充方法,以提升效率。
ChatGPT 针对我们提供的代码给出了 3 个优化建议,并详细解释了每个方法的具体含义和用法。
七、识别内存泄漏
内存泄漏是常见且令人头痛的问题,还特别难以捕捉和调试。当程序不再需要内存但没有及时回收时,就会发生内存泄漏,这最终会导致性能问题或者安全问题。ChatGPT 可以帮助识别内存泄漏问题并给出修复方法。
输入prompt:
这段代码是否存在内存泄露风险?
function calcPI(numDec) { var ans = ""; t1 = new Date(); numDec = Number(numDec) + 5; iAng = new Array(10); coeff = new Array(10); arrayLength = Math.ceil(1 + numDec / cellSize); aPI = new Array(arrayLength); aArctan = new Array(arrayLength); aAngle = new Array(arrayLength); aDivK = new Array(arrayLength); coeff[0] = 4; coeff[1] = -1; coeff[2] = 0; iAng[0] = 5; iAng[1] = 239; iAng[2] = 0; makeArray(arrayLength, aPI, 0); makeArray(arrayLength, aAngle, 0); makeArray(arrayLength, aDivK, 0); for (var i = 0; coeff[i] != 0; i++) { arctan(iAng[i], arrayLength, aArctan); Mul(arrayLength, aArctan, Math.abs(coeff[i])); if (coeff[i] > 0) Add(arrayLength, aPI, aArctan); else Sub(arrayLength, aPI, aArctan) } Mul(arrayLength, aPI, 4); sPI = ""; tempPI = ""; for (i = 0; i < aPI.length; i++) { aPI[i] = String(aPI[i]); if (aPI[i].length < cellSize && i != 0) { while (aPI[i].length < cellSize) aPI[i] = "0" + aPI[i] } tempPI += aPI[i] } for (i = 0; i <= numDec; i++) { if (i == 0) sPI += tempPI.charAt(i) + ".<br>"; else { if (document.getElementById("cbCount").checked) addcount = " (" + (i) + ")"; else addcount = ""; if (document.getElementById("cbSpace").checked) thespace = " "; else thespace = ""; if ((i) % 50 == 0 && i != 0) sPI += tempPI.charAt(i) + addcount + "<br>"; else if (i % 5 == 0) sPI += tempPI.charAt(i) + thespace; else sPI += tempPI.charAt(i) } } ans += ("PI (" + numDec + ")=" + sPI + "<br>"); ans += ("Win PI=<br>3.1415926535897932384626433832795<br>"); t2 = new Date(); timeTaken = (t2.getTime() - t1.getTime()) / 1000; ans += "It took: " + timeTaken + " seconds"; var myDiv = document.getElementById("d1"); myDiv.innerHTML = ans }
ChatGPT输出:
这段代码没有明显的内存泄露风险,因为它在函数执行期间创建的所有数组和变量都是局部作用域的,并且在函数执行结束后会自动释放。
函数内部创建了多个数组(如 iAng、coeff、aPI 等)以及一些字符串变量(如 ans 和 tempPI),它们会在函数调用结束时随着作用域的消失而被垃圾回收器清理。
变量 t1 和 t2 用于计算时间差,它们在函数结束时也会被回收。
最后,将结果赋值给 DOM 元素 myDiv.innerHTML,这不会导致内存泄露,因为这是对 DOM 树的引用更新,而不是额外增加未释放的对象引用。
然而,在实际应用中,如果该函数在一个非常大的循环或频繁调用的场景下执行,可能会因为不断创建大型数组而导致较高的内存使用率。但只要每次调用结束时能够正常回收资源,就不属于内存泄露问题。
从结果来看,ChatGPT 成功识别内存泄漏问题并给出修复建议。
综上所述,ChatGPT 是一个强大的编程辅助工具,无论是编写代码、解释代码、排查错误、重构代码,还是检查代码存在的风险和漏洞,ChatGPT 都是开发人员的好帮手。
唐代大臣魏徵的《谏太宗十思疏》中写道,“善始者实繁,克终者盖寡”。大概的意思是:如果有好多人同时做一件事情,善于开始去做的人是非常多的,但是能够把这件事做好的人就寥寥无几了。
这句千古名言可以说是非常经典了,用来形容学习编程的过程同样适合。在成为工程师、专家甚至科学家之前,困难会一直伴随着你,有多少人放弃可想而知,所以才会有了另一句:行百里者半九十。
以上测试在基于通义大模型,提供代码智能生成、研发智能问答能力的通义灵码测试,欢迎关注使用。
参见:
专访朱雷:昔日的游戏少年,如今的Python工匠_Python_图灵教育_InfoQ写作社区
Learning Curve: Theory, Meaning, Formula, Graphs [2024]
通义灵码产品介绍_智能编码助手_AI编程_云效(Apsara Devops)-阿里云帮助中心 (aliyun.com)
更多推荐
所有评论(0)