// Write a block of code using JS fetch API to get data from the server with these conditions: // 1. Request method: GET // 2. Request URL: http://localhost:3000/api/v1/contacts // 3. Request header: Content-Type: application/json: // 4. Convert the response to JSON format // The code is:随后 VSCode 便会生成代码
fetch('http://localhost:3000/api/v1/contacts', { method: 'GET', headers: { 'Content-Type': 'application/json' } }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.log(err));这对于写一些你常用、并且大致有印象、但是又不常记于心的代码非常好用。比如虽然我常写 SQL 查询语句,但是对创建或者删除数据库操作并不熟悉,于是我可以直接让它告诉我:
DROP DATABASE IF EXISTS example;
// Generate NodeJS code for sending message to AzureServiceBus: // // 1. Create a new NodeJS project // 2. Add the following to the package.json file: // "dependencies": { // "azure-sb": "^0.10.3" // } // 3. Run "npm install" // 4. Copy this file to the project folder // 5. Run "node send.js" // // Note: This sample uses the callback style of calling the send method. // There is also a promise style available. // // Documentation References: // - ServiceBus NodeJS SDK API Reference // https://docs.microsoft.com/en-us/javascript/api/azure-sb/?view=azure-node-latest // - ServiceBus NodeJS SDK Samples // // **************************************************************************************************但是如果你把这段指令放在一个名为 sendMessageToAzureServiceBus 的函数中,它会直接优先给出代码或者上面提到的链接:
async function sendMessageToAzureServiceBus() { // 堆代码 duidaima.com // Generate NodeJS code for sending message to AzureServiceBus: var azureServiceBus = require("@azure/service-bus"); var sbClient = new azureServiceBus.ServiceBusClient("<connection-string>"); var sender = sbClient.createSender("<queue-name>"); var message = { body: "Hello world" }; }因为在后者的上下文中,很明显此时此刻你更想要的是实现。
CREATE TABLE IF NOT EXISTS Item ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, price REAL NOT NULL, image TEXT, category_id INTEGER NOT NULL, FOREIGN KEY (category_id) REFERENCES Category(id) );看起来和播客关系不大是不是,但如果你一开始就把表名设计为 PodcastEpisodeItem,那么 copilot 补全结果又是另一番景象
CREATE TABLE IF NOT EXISTS PodcastEpisodeItem ( id INTEGER PRIMARY KEY AUTOINCREMENT, podcastId INTEGER NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL, pubDate TEXT NOT NULL, url TEXT NOT NULL, downloaded INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(podcastId) REFERENCES Podcast(id) )表的字段设计看上去更符合播客节目的信息了。这个技巧在编写函数时同样管用,如果你的函数名只是称为 makeSometingDouble,它生成的函数指只会是
function makeSomethingDouble(value) { return value * 2; }但如果你的目的是让数组里的每一个元素值翻倍,那么函数名最好叫 doubleArray,那么它生成的函数也会更符合你的期望
function doubleArray(array) { return array.map(item => item * 2); }文件
async function sendMessages() { const sbClient = new ServiceBusClient(connectionString); const sender = sbClient.createSender(queueName); const messages = [ { body: "Albert Einstein" }, { body: "Werner Heisenberg" }, { body: "Marie Curie" }, ]; try { for (let i = 0; i < messages.length; i++) { const message = messages[i]; console.log(`Sending message: ${message.body}`); await sender.sendMessages(message); } await sender.close(); await sbClient.close(); } catch (err) { console.log("Error occurred: ", err); } }如果你接受了这段它提供的代码,那么接下来新起一行,你无需任何输入,它即会自动提出 receiveMessages 函数:
async function receiveMessages() { const sbClient = new ServiceBusClient(connectionString); const receiver = sbClient.createReceiver(queueName); try { const messages = await receiver.receiveMessages(1); if (messages.length > 0) { console.log(`Received message: ${messages[0].body}`); await receiver.completeMessage(messages[0]); } else { console.log("No messages to receive"); } await receiver.close(); await sbClient.close(); } catch (err) { console.log("Error occurred: ", err); } }因为 azure-service-bus-service 这个名称已经提供足够窄的限制和丰富的上下文,来规范文件内代码的功能。如果你的文件只是宽泛的叫做 queue-service.js,那么当你告诉它生成一个名为 sendMessages 的函数的时候,它给出的实现也非常宽泛:
async function sendMessages() { const messages = await getMessages(); const queue = await getQueue(); await queue.sendMessages(messages); await deleteMessages(messages); }这里的 queue 可以代指不同云服务商提供的 queue 工具。
async function sendRequestToExampleAPI() { fetch('https://example.com/api', { headers: { 'Content-Type': 'application/json' }, method: 'POST', }).then((response) => { return response.json(); }).then((data) => { console.log(data); }) }那么下一个向 NewsAPI 请求数据的函数,copilot 会完全参照上述函数的实现内容生成。下面代码除了函数名词以外皆由 copilot 生成:
async function sendRequestToNewsAPI { fetch('https://newsapi.org/v2/everything?q=bitcoin&from=2020-08-29&sortBy=publishedAt&apiKey=API_KEY', { headers: { 'Content-Type': 'application/json' }, method: 'GET', }).then((response) => { return response.json(); }).then((data) => { console.log(data); }) }函数结构,“外观”一模一样。你还可以这么测试它的“抄袭”功能,不妨把第一个函数的 fetch 替换成使用 axios,那么第二个函数生成时也会改用 axios 实现
async function sendRequestToNewsAPI () { axios.get('https://newsapi.org/v2/top-headlines?country=us&apiKey=API_KEY') .then((response) => { console.log(response); }, (error) => { console.log(error); }); }注意甚至你无法阻止它抄袭其他文件内容的,我尝试在注释里告诉它 don’t refer any other code in the same space 但并不管用。
const mysql = require('mysql');这里可能会出现和你预期不符的情况,例如你想使用另一个类库完成数据库操作,在这种情况下你需要对它生成的代码做一步一步的修正。更恰当的方式其实是在文件的开头就引入特定你想使用的类库,又或者在编写完部分代码之后再对它给出指令。例如以下是我提前写出的代码:
const mysql = require('mysql2/promise') const cfg = require('./config'); const db = mysql.createPool(cfg.mysql);这样一来它便知道所有 SQL 都应该交由 mysql2 来完成,并且连接池已经为它准备完毕,在我给出指令 Write a async function to run SQL query 之后它生成的代码如下:
// Write a async function to run SQL query async function query(sql, params) { const [rows, fields] = await db.query(sql, params); return rows; }有时候你甚至需要从官方文档中黏贴一些代码片段到文件中用于给予它提示,或者在文件开头使用注释描述一下该文件的用途也同样有效,在 JetBrain 的 Marketplace 里我看到关于 Copilot 插件有这么一段简介:
74% of developers are able to focus on more satisfying work 88% feel more productive 96% of developers are faster with repetitive tasks我对其中的 repetitive tasks 深有感触,不妨回顾一下你每天的编码工作,其中有多少是重复无数次的机械劳动,有多少是听着播客或者音乐就可以完成的任务,它们都理应被 copilot 干掉。但也正如本文所示,“你”还没法被干掉,程序还需要你来主导,copilot 写出来的代码需要你来 review。