使用 v0.5.0
一些例子是“最小和简单的”,没有进行安全检查。
这是为了更好地说明概念而不是混乱的头脑,确保在您的实现中遵循良好的实践和安全编码。
让我们学习如何参数化!
教程开始
参数是编译时值。
该示例还涵盖了“结构参数推导”。
它非常有用,尝试练习玩它以记住和理解它。
注意演绎是如何“向上”向上移动的,并填补空白。
感觉参数类型定义了结构的参数,而不是相反。
提高生产率,减少屏幕空间使用,减少重复编码:
@value
struct Point3D[XT:AnyType,YT:AnyType,ZT:AnyType]:
var x:XT
var y:YT
var z:ZT
fn __init__(inout self, x:XT ,y:YT,z:ZT):
self.x = x
self.y = y
self.z = z
#
. use parameters of an argument inside the function signature:
fn to_list_literal(arg:Point3D)-> ListLiteral[arg.XT,arg.YT,arg.ZT]:
return ListLiteral(arg.x,arg.y,arg.z)
fn main():
#
Explicit struct parameters:
var my_point_d = Point3D[Int64,Int64,Int64](1,2,3)
var my_point_e = Point3D[Int64,Float64,Int64](1,2.5,3)
#
Struct parameters deduction
#XT, YT, ZT deduced from argument passed:
var my_point_a = Point3D(1, 2, 3) #Int64, Int64, Int64
var my_point_b = Point3D(1.0, 2.0, 3.0) #Float64, Float64, Float64
var my_point_c = Point3D(1, 2.5, 3) #Int64, Float64, Int64
#
Re-use the parameters of an instance of Point3D
var some:my_point_c.YT = 1.0 #my_point_c.YT is a type (Float64)
print(to_list_literal(my_point_a)) # [1, 2, 3]
print(to_list_literal(my_point_c)) # [1, 2.5, 3]
详见更新日志:v0.5.0-2023-11-2
现在可以在函数的签名中引用函数参数输入参数
Mojo 现在支持结构参数推导
功能自动参数化
我们不接受 arg 的参数,但 DynamicVector 是参数化的。take_dynamic_vector()
长格式版本可能如下所示:
fn take_dynamic_vector[T:AnyType](arg:DynamicVector[T]) -> T:
Mojo 将为我们创建论文以提高工作效率。
为了理解语言,了解这一点很重要。
fn take_dynamic_vector(arg:DynamicVector) -> arg.type:
let tmp: arg.type = arg[0] #first element of vector
return tmp
fn main():
var tmp_a = DynamicVector[Int64]()
var tmp_b = DynamicVector[Float64]()
var tmp_c = DynamicVector[Bool]()
tmp_a.push_back(1)
tmp_b.push_back(1.5)
tmp_c.push_back(True)
let a:Int64 = take_dynamic_vector(tmp_a)
let b = take_dynamic_vector(tmp_b)
print(a,b)
#parameters are known at compile time
#type is a parameter of DynamicVector
let d:tmp_c.type = False #tmp_c.type == Bool
let e = take_dynamic_vector(tmp_c)
print(d==e)
需要时“拉取”参数:
请注意,我们指的是函数签名本身内部的 arg 参数。
fn simd_to_dtype_pointer(arg:SIMD)->DTypePointer[arg.type]:
var tmp = DTypePointer[arg.type].alloc(arg.size)
# just to demonstrate unroll,
# simd_store is probably way faster:
@unroll
for i in range(arg.size):
tmp.store(i,arg[i])
return tmp
fn simd_to_static_tuple(arg:SIMD)->StaticTuple[arg.size,SIMD[arg.type,1]]:
var tmp = StaticTuple[arg.size,SIMD[arg.type,1]]()
#Can be unrolled, because arg.size is known at compile time.
#Parameters of simd: SIMD[TYPE,SIZE]
@unroll
for i in range(arg.size):
tmp[i]=arg[i]
return tmp
编译器时间常量值(例如别名或参数)是展开循环所必需的。
捕获函数中的动态值并将其作为参数传递
目前 (v0.5) 是不安全的,直到通过引用对捕获值的生存期进行建模。
参见文档:参数装饰器
为了熟悉它,这里是一个介绍:
fn take_parameter[f: fn() capturing -> Int]():
let val = f()
print(val)
fn main():
#will be captured as a reference
var val = 0
@parameter
fn closure()->Int:
return val #captured here
for i in range(5):
val = i
take_parameter[closure]()
_ = val #extend lifetime manually
#if not extended, would be cleaned at last use.
编译时 if 语句
它是在编译时运行的 if 语句。
这样做的好处是,最终程序中只包含实时分支。
alias use_simd:Bool = SIMD[DType.uint8].size > 1
fn main():
@parameter
if use_simd == True:
print("This build uses simd")
else:
print("This build do not uses simd")
每次都会执行在运行时运行的传统 if 语句。
在编译过程中,该命令仅执行一次。
如果满足条件,if 语句块中的内容将包含在程序中。
它引入了一种条件编译的形式。
请注意,任何“编译时就绪”函数都可以在 if 语句中使用。
alias
对于编译时常量,
它们可以作为参数传递,因为它们在编译时是已知的。
fn main():
alias size = 4
alias DT = DType.uint8
var value = SIMD[DT,size](0)
print(value.size==size)
#create an alias to the print_no_newline function
alias say = print_no_newline
say("hello world")
它们也可以“像 C 中的定义一样”使用
alias TYPE_OF_INT = Int64
fn get_vector()->DynamicVector[TYPE_OF_INT]:
return DynamicVector[TYPE_OF_INT]()
fn my_add(a:TYPE_OF_INT,b:TYPE_OF_INT)->TYPE_OF_INT:
return a+b
因为别名是“编译时”,所以它可以存储编译时计算的结果:
fn squared(a:Int) -> Int:
return a*a
fn main():
alias pre_calculated_during_compilation = squared(3)
var calculated_during_runtime = squared(3)
print(pre_calculated_during_compilation) #9
alias squared_again_during_compilation = squared(pre_calculated_during_compilation)
print(squared_again_during_compilation) #81
在编译时,可以分配堆内存并将其具体化以供运行时使用。
fn get_squared[stop_at:Int=10]() -> DynamicVector[Int]:
var tmp = DynamicVector[Int]()
for i in range(stop_at):
tmp.push_back(i*i)
return tmp
fn main():
alias the_compile_time_vector = get_vector[stop_at=100]()
var materialized_for_runtime_use = the_compile_time_vector
参数默认值和关键字
参数可以具有默认值,并由关键字引用。
具有默认值的那些需要在那些没有默认值(顺序)之后定义。
example[no_default:Int, got_default:Int=1]
fn get_vector[VT:AnyType = Int64]()->DynamicVector[VT]:
return DynamicVector[VT]()
fn main():
var vec = get_vector()
vec.push_back(1)
var vec2 = get_vector[VT=Int32]()
vec2.push_back(1)
重载:同名,不同类型。
可以在参数和函数/方法上进行重载。
fn take_arg[arg:Float64]():
print("float64", arg)
fn take_arg[arg:Int64]():
print("Int64", arg)
fn main():
alias a:Float64 = 1.0
alias b:Int64 = 1
take_arg[a]()
take_arg[b]()