V语言10共享对象

共享对象

通过共享对象协程/线程间交换数据.应按共享创建并传递给协程.底层包含一个来锁住并发访问,rlock针对只读,而lock针对读写.

struct St {
mut:
	x int //待共享数据
}

fn (shared b St) g() {//共享函数
	lock b {
		// 读改写 b.x
	}
}

fn main() {
	shared a := St{
		x: 10
	}
	go a.g()
	// ...
	rlock a {
		// 读a.x
	}
}

共享变量必须为构,数组,映射.

import json

struct Foo {
	x int
}

struct User {
	name string
	age  int
	// 用跳过属性来跳过特定字段
	foo Foo [skip]
	//如果字段名与数格不同,可指定
	last_name string [json: lastName]
}

data := "{ "name": "Frodo", "lastName": "Baggins", "age": 25 }"
user := json.decode(User, data) or {
	eprintln("解码数格失败")
	return
}
println(user.name)
println(user.last_name)
println(user.age)
// 也可解码数格数组
sfoos := "[{"x":123},{"x":456}]"
foos := json.decode([]Foo, sfoos) ?
println(foos[0].x)
println(foos[1].x)

V内置支持数格.json.decode带两个参数:1为类型,2为串.
V生成加解密数格代码,无运行时反射,性能更好.

测试

fn foo(mut v []int) {
	v[0] = 1
}

mut v := [20]
foo(mut v)
assert v[0] < 4

assert检查表达式为.失败则中止程序.应仅用来检测编程错误,错误时打印出比较两端值.

// 你好.v
module main

fn 你好() string {
	return "你好啊"
}

fn main() {
	println(你好())
}
//主
module main

// 你好_test.v
fn test_你好() {
	assert 你好() == "你好啊"
}

v 你好_test.v命令.v在文件中执行所有测试函数.

序号注意
1必须以_test.v结尾,
2测试函数以test_开始,
3普通函数也可在测试中,但要手动调用,
4有两类测试:外部/内部.
5内部测试必须声明模块名,可调用相同模块私函数
6外部测试必须导入待测试模块,仅能测试模块的外部/公开函数.

上面为内部测试,内部测试可用来测试私有函数
测试函数中特殊函数:testsuite_begin/end在其他测试函数前后运行.

import strconv

fn test_atoi() ? {
	assert strconv.atoi("1") ? == 1
	assert strconv.atoi("one") ? == 1 // test will fail
}

一个错误,就传播了.运行单个测试文件:v foo_test.v.
测试整个模块,v test mymodule/v test ..-stats获取测试细节.你可在测试目录中放testdata文件夹.特殊处理,都可这样.
V编译器路径可由@VEXE得到.

import os

fn test_subtest() {
	res := os.execute("${@VEXE} other_test.v")
	assert res.exit_code == 1
	assert res.output.contains("other_test.v 不存在")
//这样就可编译测试文件了.
}

管理内存

V第一时间用值类型/串缓冲来避免不必要分配.大多数代码>90%自动释放引擎释放.编译期插入释放代码,剩余小部分用引用计数释放.
开发者不必改代码,就管用了.没有厚重垃圾跟踪昂贵引用计数.
你可利用V的自动释放引擎,并对自己的类型定义释放.

struct MyType {}

[unsafe]
fn (data &MyType) free() {
	// ...
}//手动释放了.就像C++的析构函数

可用-manualfree开关来手动管理内存,用于低级控制.函数上加[manualfree]也可以.当前默认为-autofree开关.不自动释放,会泄露内存.

import strings

fn draw_text(s string, x int, y int) {
	// ...
}

fn draw_scene() {
	// ...
	name1 := "abc"
	name2 := "def ghi"
	draw_text("你好 $name1", 10, 10)
	draw_text("你好 $name2", 100, 10)
	draw_text(strings.repeat(`X`, 10000), 10, 50)
	// ...
}

不转义draw_text,所以退出函数,就清理了.
-prealloc标志,前2个根本不分配.是小串,所以给他们用预分配缓冲.

struct User {
	name string
}

fn test() []int {
	number := 7 // 栈变量
	user := User{} // 栈上构
	numbers := [1, 2, 3] //堆上分配数组,退出函数时释放
	println(number)
	println(user)
	println(numbers)
	numbers2 := [4, 5, 6] //返回,因而不释放
	return numbers2
}

ORM

α状态,支持SQLite, MySQL和Postgres,将支持MS SQL和Oracle

序号好处
1统一语法
2统一查询
3安全
4编译时检查
5可读性/简单性
import sqlite

struct Customer {
	//目前构名必须与表名相同
	id  int    [primary; sql: serial] //`id`必须为第1字段
	name      string [nonull]
	nr_orders int
	country   string [nonull]
}

db := sqlite.connect("customers.db") ?

// 可创建表
// CREATE TABLE IF NOT EXISTS `Customer` (`id` INTEGER PRIMARY KEY, `name` TEXT NOT NULL, `nr_orders` INTEGER, `country` TEXT NOT NULL)
sql db {
	create table Customer
}

// select count(*) from Customer
nr_customers := sql db {
	select count from Customer
}
println("顾客数: $nr_customers")
// 用V语法来构建查询
uk_customers := sql db {
	select from Customer where country == "uk" && nr_orders > 0
}
println(uk_customers.len)
for customer in uk_customers {
	println("$customer.id - $customer.name")
}
// 添加`limit 1`告诉V,只1个对象
customer := sql db {
	select from Customer where id == 1 limit 1
}
println("$customer.id - $customer.name")
// 插入新顾客
new_customer := Customer{
	name: "张三"
	nr_orders: 10
}
sql db {
	insert new_customer into Customer
}
posted @   zjh6  阅读(15)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示