以 ! 结尾的函数会改变参数的内容,但是可以定义不以 ! 结尾的函数也能够更改参数的内容,以 ! 结尾是否是一种约定而不是一种语法规定?例子如下:
julia> function f(x)
push!(x,1)
end
f (generic function with 1 method)
julia> a=[]
0-element Array{Any,1}
julia> f(a)
1-element Array{Any,1}:
1
julia> a
1-element Array{Any,1}:
1
如果以 ! 结尾只是一种约定,为什么标准库里的函数write更改了参数IOBuffer的内容却不定义为write! ?
julia> io = IOBuffer()
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)
julia> write(io, "abcd")
4
julia> String(take!(io))
"abcd"
以!结尾的函数,这种写法是一种约定,表示会带来副作用
下面的我就不知道了
函数带!应该是警告该函数会改变引用参数所指向的原始数据,而不是拷贝,这只是一个约定,不是语法
后缀 !
是一种约定。
write
不加可能是出于习惯吧,输出到 io 的 print
系的函数也是都没有加。
好吧,可能确实是这样。我还想既然是约定,为什么官方自己都不遵守。
目前我知道的语言里,严格遵守这个规定的只有Rust
了,他们的println!
要加个叹号,老的lisp
里不用这样做,所以这不是官方的问题,是个习惯问题
更准确地说,!
约定是表示这个函数是 in-place 方法,只是恰好in-place 方法需要从外部导入一个数据并修改它。更多地是为了区分 in-place 与 copy 的方法。 print 和 write 这些并不存在所谓copy的方法也就没有必要强制遵守这个约定。
5 个赞
Rust
加 !
因为那代表一个宏,是语法规定。Julia
宏则强制要求 @
, Julia
这般强大的宏如果不带 @
的话会可能重蹈 lisp
的覆辙,搞出一堆方言引发社区分裂。
Roger
2020 年7 月 24 日 22:46
10
Julia的类型系统本身不能区分mutation操作,所以!只是约定,另外就是作为一个有GC的语言在内存的问题上相对来说更省事一些。而实际上有很多不带!的函数也会改变全局变量,例如rand等等。
rust语言在设计的时候为了严格保证内存安全的零开销抽象,rust的编译器可以做到正确区分mutation操作,所以rust里!可以作为一个语法。
1 个赞