1. Instalación, v run, módulos y proyectos
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Código: examples/l01_hello.v, examples/l01_script.v y el proyecto l01-project.
Cómo construye V un programa
Sección titulada «Cómo construye V un programa»| C# | Java | V | |
|---|---|---|---|
| El compilador produce | IL en un .dll |
bytecode en archivos .class |
código C, en un archivo temporal |
| Después | el CLR compila el IL en tiempo de ejecución (JIT) | la JVM interpreta y compila el bytecode (JIT) | un compilador C convierte el C en un ejecutable nativo |
| Para ejecutarlo necesitas | el runtime de .NET, salvo si publicas autocontenido o con Native AOT | una JVM, o una imagen jlink |
nada: el ejecutable es nativo |
V incluye un compilador C, TCC (Tiny C Compiler), en thirdparty/tcc de cada archivo de versión. TCC compila rápido y optimiza poco: V lo usa para las compilaciones del día a día, y el compilador C del sistema (gcc, clang o MSVC) para las compilaciones optimizadas con -prod. v -showcc imprime el comando del compilador C. La CI del curso muestra qué compilador construye el «Hello World» de v new, y qué tamaño tiene el resultado:
| SO | v . |
tamaño | v -prod . |
tamaño |
|---|---|---|---|---|
| Windows (mi máquina) | tcc.exe |
281,600 bytes | MSVC cl.exe |
29,184 bytes |
| Windows (runner de CI) | tcc.exe |
280,576 bytes | gcc (MinGW) |
160,784 bytes |
| Linux (runner de CI) | tcc.exe |
385,782 bytes | cc (gcc 13.3) |
138,296 bytes |
| macOS (runner de CI) | cc (Apple clang) |
96,808 bytes | cc (Apple clang) |
126,408 bytes |
En macOS, V eligió cc incluso sin -prod. En Windows, -prod usa el compilador C que encuentre: MSVC en mi máquina, que tiene las Visual Studio Build Tools y no tiene gcc, y gcc de MinGW en el runner. La lección 4 muestra por qué esa elección importa para la memoria.
Instalación
Sección titulada «Instalación»La documentación recomienda compilar V desde el código fuente con git clone y make, lo que sigue la rama master. Este curso fija en cambio la versión 0.5.2 y descarga su archivo: uno por SO, con v, la biblioteca estándar, las herramientas y TCC. Lo instalo en una carpeta propia y no lo pongo en el PATH global.
Invoke-WebRequest https://github.com/vlang/v/releases/download/0.5.2/v_windows.zip -OutFile v_windows.zipExpand-Archive v_windows.zip -DestinationPath C:\tools # crea C:\tools\v (tardó 53 s en mi máquina)C:\tools\v\v.exe versionPara llamarlo v desde cualquier terminal, añade C:\tools\v a tu PATH, o ejecuta v.exe symlink en una shell de administrador, como describe el README (por verificar: no lo he ejecutado).
curl -fLO https://github.com/vlang/v/releases/download/0.5.2/v_linux.zip # v_linux_arm64.zip en ARMunzip -q v_linux.zip -d ~/tools # crea ~/tools/v~/tools/v/v versionexport PATH="$HOME/tools/v:$PATH" # añádelo a ~/.bashrc para conservarloEl archivo conserva los bits de ejecución de v y de thirdparty/tcc/tcc.exe (sí, con .exe, también en Linux). TCC necesita las cabeceras C del sistema; el runner Ubuntu 24.04 las tiene. En una distribución mínima, instala build-essential o su equivalente (por verificar).
En WSL, instala el archivo de Linux dentro de la distribución, y guarda tus proyectos en el sistema de archivos de Linux (~/src/...), no bajo /mnt/c.
xcode-select --install # las herramientas de línea de comandos de Apple: V compila con cc en macOScurl -fLO https://github.com/vlang/v/releases/download/0.5.2/v_macos_arm64.zip # v_macos_x86_64.zip en Intelunzip -q v_macos_arm64.zip -d ~/tools # crea ~/tools/v~/tools/v/v versionexport PATH="$HOME/tools/v:$PATH" # añádelo a ~/.zshrc para conservarlocurl no pone el atributo de cuarentena; un archivo descargado con un navegador puede necesitar xattr -dr com.apple.quarantine ~/tools/v antes de que macOS ejecute v (por verificar).
Después, en cualquier SO:
> v versionV 0.5.2 7647ce1v doctor imprime lo que V encontró: su carpeta, la carpeta VMODULES donde van los paquetes, y cada compilador C. En mi máquina:
|V full version |V 0.5.2 45ae01d23168b6372f734eeb38a77360bbcf184a.7647ce1|V executable |C:\Users\spare\tools\v-0.5.2\v.exe|VMODULES |OK, value: C:\Users\spare\.vmodules|cc version |N/A|gcc version |N/A|clang version |N/A|msvc version |N/A|tcc version |tcc version 0.9.27 (x86_64 Windows)v doctor dice msvc version N/A, y sin embargo v -prod encontró MSVC a través de la instalación de las Build Tools.
Hola, mundo
Sección titulada «Hola, mundo»fn main() { println('Hello, world!')}> v run examples/l01_hello.vHello, world!| C# | Java | V | |
|---|---|---|---|
| Compilar y ejecutar un archivo | dotnet run app.cs (.NET 10) |
java Hello.java |
v run hello.v |
| Solo compilar | dotnet build |
javac Hello.java |
v hello.v, que escribe hello.exe o hello |
| Compilación optimizada | dotnet publish -c Release |
— | v -prod hello.v |
v run compila a un ejecutable temporal, lo ejecuta y lo borra. Las opciones del compilador van antes de run; todo lo que sigue al nombre del archivo va a tu programa.
fndeclara una función; el tipo de retorno, si lo hay, va después de los parámetros.printlnes una función integrada: sin import, sinConsole.niSystem.out..- Las cadenas usan comillas simples;
v fmtconvierte las comillas dobles en simples. - No hay punto y coma, y el código V se indenta con tabulaciones.
Scripts: sin fn main
Sección titulada «Scripts: sin fn main»Un único archivo puede prescindir de fn main, como las instrucciones de nivel superior en C# o un archivo fuente compacto en Java 25:
fn greeting(name string) string { return 'Hello, ${name}!'}
println(greeting('C#'))println(greeting('Java'))Hello, C#!Hello, Java!${…} interpola una expresión en una cadena, como $"…{name}" en C#. El orden es el contrario que en C#, donde las instrucciones de nivel superior deben ir antes de las declaraciones de tipos: en un script V, las definiciones van primero, y una función después de la primera instrucción se rechaza.
fn greeting(name string) string { return 'Hello, ${name}!'}
println(greeting('C#'))
fn farewell(name string) string { return 'Bye, ${name}!'}e01_script_order.v:5:1: notice: script mode started here 3 | } 4 | 5 | println(greeting('C#')) | ~~~~~~~ 6 | 7 | fn farewell(name string) string {e01_script_order.v:7:4: error: all definitions must occur before code in script mode 5 | println(greeting('C#')) 6 | 7 | fn farewell(name string) string { | ~~~~~~~~ 8 | return 'Bye, ${name}!' 9 | }El compilador imprime los errores en la salida de error estándar, con el archivo, la línea y la columna, y termina con el código 1.
Un proyecto: v new y v.mod
Sección titulada «Un proyecto: v new y v.mod»v new hellov new hace tres preguntas (descripción, versión, licencia) y crea una carpeta:
hello/├── .editorconfig├── .gitattributes├── .gitignore├── main.v ← module main, fn main└── v.mod ← como .csproj o pom.xml, pero solo metadatosModule { name: 'hello' description: 'Greets people' version: '0.0.0' license: 'MIT' dependencies: []}También ejecuta git init cuando Git está instalado. v init hace lo mismo en una carpeta existente.
Las respuestas se leen de la entrada estándar: si está cerrada, como en un script sin entrada, v new no se detiene, y escribe '<EOF>' en los tres campos. os.input devuelve esa cadena al final de la entrada (os.v, líneas 436-441), y vcreate.v solo sustituye una respuesta vacía por el valor por defecto. La CI responde con printf 'Greets people\n\n\n' | v new hello.
v run . compila todos los archivos .v de la carpeta en un solo programa, que lleva el nombre de la carpeta:
> cd hello> v run .Hello World!No hay archivo de compilación que mantener: V encuentra los archivos y los módulos a partir de las carpetas. v.mod da nombre al proyecto, lista sus dependencias y marca la raíz desde la que import encuentra los módulos del proyecto.
Módulos
Sección titulada «Módulos»Un módulo es una carpeta. Cada archivo .v de la carpeta empieza por module <nombre de la carpeta>, y todos ven las declaraciones de los demás; los archivos de la raíz del proyecto son module main.
l01-project/├── v.mod├── main.v└── greet/ └── greet.vmodule greet
// hello es público: otros módulos pueden llamarlo como `greet.hello`pub fn hello(name string) string { return 'Hello, ${capitalize(name)}!'}
// capitalize es privado del módulo, como `internal` en C# o package-private en Javafn capitalize(s string) string { return s.capitalize()}module main
import osimport greet
fn main() { names := if os.args.len > 1 { os.args[1..] } else { ['world'] } for name in names { println(greet.hello(name)) }}> v run .Hello, World!> v run . ada graceHello, Ada!Hello, Grace!os.args contiene la ruta del programa y después sus argumentos: os.args[1..] omite la ruta, como string[] args en C# y Java.
| C# | Java | V | |
|---|---|---|---|
| Unidad | namespace, independiente de las carpetas |
package, una carpeta |
módulo, una carpeta |
| Importación | using Greet; |
import greet.*; |
import greet |
| Llamada | Greeter.Hello(…) |
Greeter.hello(…) |
greet.hello(…): siempre con el nombre del módulo |
| Público | public |
public |
pub |
| Por defecto | internal (el ensamblado) para un tipo, private para un miembro |
package-private | privado del módulo |
Sin pub, otro módulo no puede llamar a la función:
module main
import greet
fn main() { println(greet.capitalize('java'))}main.v:6:16: error: function `greet.capitalize` is private 4 | 5 | fn main() { 6 | println(greet.capitalize('java')) | ~~~~~~~~~~~~~~~~~~ 7 | }Dos reglas más de la documentación de los módulos: las importaciones no pueden ser circulares, y un módulo en a/b/ se importa como a.b pero se llama con su último nombre, b.hello().
Comandos del día a día
Sección titulada «Comandos del día a día»| Tarea | V | dotnet | Java |
|---|---|---|---|
| Nueva app | v new app |
dotnet new console |
mvn archetype:generate |
| Ejecutar una carpeta | v run . |
dotnet run |
mvn exec:java |
| Compilar | v . |
dotnet build |
mvn compile |
| Compilación optimizada | v -prod . |
dotnet publish -c Release |
mvn package |
| Probar | v test . |
dotnet test |
mvn test |
| Formatear | v fmt -w . |
dotnet format |
un plugin como Spotless |
| Análisis estático (lint) | v vet . |
analizadores de Roslyn | Error Prone |
| Comprobar la instalación | v doctor |
dotnet --info |
java -XshowSettings |
v help <command> documenta cada comando. Las pruebas, v fmt, v vet y v doc son el tema de la lección 8, los paquetes el de la lección 12.
Puntos clave
Sección titulada «Puntos clave»- V traduce tu programa a C, y un compilador C genera el ejecutable: TCC, incluido con V, para las compilaciones del día a día;
gcc,clango MSVC con-prod. v run file.vov run .compila y ejecuta;v file.vov .solo compila.- Un único archivo puede prescindir de
fn main, si todas las definiciones van antes de la primera instrucción. - Un módulo es una carpeta; una función es privada de su módulo salvo que sea
pub, y siempre se llama con el nombre del módulo. v.modcontiene los metadatos del proyecto; no hay lista de archivos que mantener.
Ejercicios
Sección titulada «Ejercicios»- Mueve
fn greetingdel01_script.vdebajo de las dos llamadas aprintln. ¿Qué dice el compilador, y por qué no funciona el mismo orden en un script?
Solución
error: all definitions must occur before code in script modeEn un archivo sin fn main, V crea un main implícito desde la primera instrucción hasta el final del archivo (modo script): una función declarada después de ese punto estaría dentro de main. En un archivo con fn main, el orden no importa: V eleva (hoisting) todas las declaraciones.
- Añade un módulo
statsa una copia del01-project, con una función públicaword_count(s string) int, e imprime el número de palabras de los argumentos del programa.
Solución
module stats
// word_count cuenta las palabras separadas por espaciospub fn word_count(s string) int { return s.fields().len}module main
import osimport greetimport stats
fn main() { text := os.args[1..].join(' ') println(greet.hello('reader')) println('${stats.word_count(text)} words')}> v run . V for C# and Java developersHello, Reader!6 wordsNo cambia nada más: ningún archivo de proyecto que editar, import stats encuentra la carpeta junto a v.mod. fields divide por los espacios en blanco.
- Compila
l01-projectconv -showcc .y conv -showcc -prod .. ¿Qué compilador C usa cada compilación en tu máquina, y qué tamaño tienen los dos ejecutables?
Solución
La primera línea que empieza por > C compiler cmd: nombra el compilador. En Windows y Linux, la primera compilación usa thirdparty/tcc/tcc.exe; la compilación -prod usa gcc, cc o MSVC, el que encuentre V. En macOS, ambas usan cc. Compara tus tamaños con la tabla del principio de esta lección: el tamaño depende tanto del compilador C como de -prod, ya que en el runner de macOS la compilación -prod es la más grande.
Fuentes
Sección titulada «Fuentes»- Documentación de V — Hello World, Running a project folder, Modules, Module imports
- README de V — instalación de V
- Versión 0.5.2 de V
v help— el texto de cada página dev help- Microsoft — File-based apps, JEP 330 — Launch single-file source-code programs, JEP 512 — Compact source files and instance main methods