V语言06函数
函数
V
默认为纯
函数,除了io
无副作用.
这通过无全局
变量及即使传递引用,函数参数默认不变
,但V
并非纯函数式语言.
编译器,有-enable-globals
选项来启用全局变量
,针对低级应用(内核,驱动)
.
可变参数
用变
来允许参数可变:
struct User {
name string
mut:
is_registered bool
}
fn (mut u User) register() {
u.is_registered = 真
}//对象.`接收器`可变
mut user := User{}
println(user.is_registered) // "假"
user.register()
println(user.is_registered) // "真"
//其他参数也一样
fn multiply_by_2(mut arr []int) {//也要加变
for i in 0 .. arr.len {
arr[i] *= 2
}
}
mut nums := [1, 2, 3]
//也要加变
multiply_by_2(mut nums)
println(nums)
// "[2, 4, 6]"
最好返回值,而不是修改参数.在减少分配/复制
时用参数返回
.
因而V
不允许修改作为参数的基本类型
(如整),仅允许数组/映射
可修改.
用user.register()或user=register(user)
来替换register(mut user)
返回修改版的对象.
struct User {
name string
age int
is_registered bool
}
fn register(u User) User {
return {
...u//这样.
is_registered: true
}
}
mut user := User{
name: "abc"
age: 23
}
user = register(user)
println(user)
可变参数
fn sum(a ...int) int {
mut total := 0
for x in a {
total += x
}
return total
}//用...整来表可变
println(sum()) // 0
println(sum(1)) // 1
println(sum(2, 3)) // 5
// 分解数组
a := [2, 3, 4]
println(sum(...a)) // <--用...前缀来解包
b := [5, 6, 7]
println(sum(...b)) // output: 18
//C++是用后缀来解包.
匿名/高阶函数
:
fn sqr(n int) int {
return n * n
}
fn cube(n int) int {
return n * n * n
}
fn run(value int, op fn (int) int) int {
return op(value)
}//函数.前面为值,后面为类型.
fn main() {
//函数可传递给其他函数
println(run(5, sqr)) // "25"
//λ函数可在其他函数中定义/声明
double_fn := fn (n int) int {
return n + n
}
println(run(5, double_fn)) // "10"
//不赋值变量下传递函数
res := run(5, fn (n int) int {
return n + n
})
println(res) // "10"
//函数数组/映射
fns := [sqr, cube]
println(fns[0](10)) // "100"
fns_map := map{
"sqr": sqr
"cube": cube
}
println(fns_map["cube"](2)) // "8"
}
引用
struct Foo {}
fn (foo Foo) bar_method() {
// ...
}
fn bar_function(foo Foo) {
// ...
}
函数参数不变
,则由编译器
决定是值/引用
传递,不用记按引用/值
传递.加上&
确保总是按引用传递:
struct Foo {
abc int
}
fn (foo &Foo) bar() {//&按引用.
println(foo.abc)
}//`foo`仍是不变的,否则用(mut foo Foo)
V引用
类似Go指针/C++引用
.通用树:
struct Node<T> {
val T
left &Node<T>
right &Node<T>
}
常数
const (
pi = 3.14
world = "世界"
)//用`常`来定义`常数`.这里声明多个常.
println(pi)
println(world)
只能在模块
级别定义常数
.这个常是不变
的意思.
也可const e = 2.71828
单独声明常
.
V
常更灵活,你可赋值多个复杂值.
struct Color {
r int
g int
b int
}
fn rgb(r int, g int, b int) Color {
return Color{
r: r
g: g
b: b
}
}
const (//多个赋值
numbers = [1, 2, 3]
red = Color{
r: 255
g: 0
b: 0
}
// 编译时求值-->现在是启动时程序求值了.
blue = rgb(0, 0, 255)
)//相当于一个区块了.
println(numbers)
println(red)
println(blue)
禁止全局变量
,因而用常
块.用公
可导出常数
.
module mymodule
pub const golden_ratio = 1.61803
fn calc() {
println(mymodule.golden_ratio)
}
常块(常())
前面不能有公
.外部用常
,必须加模块名
.
常量用snake_case
,为区别本地变量,要加模块名
.为用π
,内外都要用math.pi
.只在主
模块中放松,由vfmt
考虑,你在数学
模块中用pi
最后会加上数学
.
println(pi)//变成
println(math.pi)
内置函数
下为完整列表
fn print(s string) //输出中打印
fn println(s string) //打印并加换行
fn eprint(s string) //输出在错误
fn eprintln(s string) //
fn exit(code int) //用自定义错误码退出程序
fn panic(s string) //错误中打印消息并跟踪,用1错误码退出
fn print_backtrace() //打印跟踪栈
打印,可打印strings,numbers,arrays,maps,structs
.
struct User {
name string
age int
}
println(1) // "1"
println("hi") // "hi"
println([1, 2, 3]) // "[1, 2, 3]"
println(User{ name: "Bob", age: 20 }) // "User{name:"Bob", age:20}"
//自定义,加个`串`函数
struct Color {
r int
g int
b int
}
pub fn (c Color) str() string {
return "{$c.r, $c.g, $c.b}"
}
red := Color{
r: 255
g: 0
b: 0
}
println(red)
根目录下所有文件,均为相同模块的部分.简单程序不必指定模块
名,默认为主
.
V
是模块化语言,鼓励创建可重用模块
,
// myfile.v之上为mymodule目录
module mymodule
//导出用公
pub fn say_hi() {
println("我的模块,你好")
}
//外部使用
import mymodule
fn main() {
mymodule.say_hi()
}
序号 | 注意 |
---|---|
1 | 模块名要短,<10 个符. |
2 | 用snake_case 格式 |
3 | 禁止循环导入 |
4 | 所有模块静态编译至exe 文件 |
模块的初化
函数
fn init() {
//模块级初化代码,初化C库很有用.
}//抄的D的静态模块构造,可为公,自动调用该函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现