mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
docs: small fixes in the doc (#10840)
This commit is contained in:
parent
d84ffbf73c
commit
6bf69ea3e3
53
doc/docs.md
53
doc/docs.md
@ -3687,14 +3687,14 @@ Due to performance considerations V tries to put objects on the stack if possibl
|
|||||||
but allocates them on the heap when obviously necessary. Example:
|
but allocates them on the heap when obviously necessary. Example:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
struct RefStruct {
|
|
||||||
r &MyStruct
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyStruct {
|
struct MyStruct {
|
||||||
n int
|
n int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RefStruct {
|
||||||
|
r &MyStruct
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
q, w := f()
|
q, w := f()
|
||||||
println('q: $q.r.n, w: $w.n')
|
println('q: $q.r.n, w: $w.n')
|
||||||
@ -3751,7 +3751,7 @@ fn (mut a MyStruct) f(b &MyStruct) int {
|
|||||||
Here the call `q.f(&w)` passes references to `q` and `w` because `a` is
|
Here the call `q.f(&w)` passes references to `q` and `w` because `a` is
|
||||||
`mut` and `b` is of type `&MyStruct` in `f()`'s declaration, so technically
|
`mut` and `b` is of type `&MyStruct` in `f()`'s declaration, so technically
|
||||||
these references are leaving `main()`. However the *lifetime* of these
|
these references are leaving `main()`. However the *lifetime* of these
|
||||||
references lies inside the scop of `main()` so `q` and `w` are allocated
|
references lies inside the scope of `main()` so `q` and `w` are allocated
|
||||||
on the stack.
|
on the stack.
|
||||||
|
|
||||||
#### Manual Control for Stack and Heap
|
#### Manual Control for Stack and Heap
|
||||||
@ -3759,10 +3759,10 @@ on the stack.
|
|||||||
In the last example the V compiler could put `q` and `w` on the stack
|
In the last example the V compiler could put `q` and `w` on the stack
|
||||||
because it assumed that in the call `q.f(&w)` these references were only
|
because it assumed that in the call `q.f(&w)` these references were only
|
||||||
used for reading and modifying the referred values – and not to pass the
|
used for reading and modifying the referred values – and not to pass the
|
||||||
references itself somewhere else. This can be seen in a way that the
|
references themselves somewhere else. This can be seen in a way that the
|
||||||
references to `q` and `w` are only *borrowed* to `f()`.
|
references to `q` and `w` are only *borrowed* to `f()`.
|
||||||
|
|
||||||
Things become different if `f()` is doing something with the references itself:
|
Things become different if `f()` is doing something with a reference itself:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
struct RefStruct {
|
struct RefStruct {
|
||||||
@ -3806,7 +3806,7 @@ refer to an object stored on stack"*. The assumption made in `g()` that the call
|
|||||||
|
|
||||||
A solution to this dilemma is the `[heap]` attribute at the declaration of
|
A solution to this dilemma is the `[heap]` attribute at the declaration of
|
||||||
`struct MyStruct`. It instructs the compiler to *always* allocate `MyStruct`-objects
|
`struct MyStruct`. It instructs the compiler to *always* allocate `MyStruct`-objects
|
||||||
on the heap. This way the references to `s` remains valid even after `g()` returns.
|
on the heap. This way the reference to `s` remains valid even after `g()` returns.
|
||||||
The compiler takes into consideration that `MyStruct` objects are always heap
|
The compiler takes into consideration that `MyStruct` objects are always heap
|
||||||
allocated when checking `f()` and allows assigning the reference to `s` to the
|
allocated when checking `f()` and allows assigning the reference to `s` to the
|
||||||
`r.r` field.
|
`r.r` field.
|
||||||
@ -3820,8 +3820,8 @@ fn (mut a MyStruct) f() &MyStruct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here `f()` is passed a reference `a` that is passed back to the caller and returned
|
Here `f()` is passed a reference `a` as receiver that is passed back to the caller and returned
|
||||||
at the same time. The intention behind such a declaration is method chaining like
|
as result at the same time. The intention behind such a declaration is method chaining like
|
||||||
`y = x.f().g()`. However, the problem with this approach is that a second reference
|
`y = x.f().g()`. However, the problem with this approach is that a second reference
|
||||||
to `a` is created – so it is not only borrowed and `MyStruct` has to be
|
to `a` is created – so it is not only borrowed and `MyStruct` has to be
|
||||||
declared as `[heap]`.
|
declared as `[heap]`.
|
||||||
@ -3861,26 +3861,16 @@ There is an alternative way to manually control allocation on a case to case bas
|
|||||||
approach is not recommended but shown here for the sake of completeness:
|
approach is not recommended but shown here for the sake of completeness:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
struct MyStruct {
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
struct RefStruct {
|
struct RefStruct {
|
||||||
mut:
|
mut:
|
||||||
r &MyStruct
|
r &MyStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyStruct {
|
// simple function - just to overwrite stack segment previously used by `g()`
|
||||||
n int
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut r RefStruct) f(s &MyStruct) {
|
|
||||||
r.r = unsafe { s } // override compiler check
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut r RefStruct) g() {
|
|
||||||
s := &MyStruct{ // `s` explicitly referes to a heap object
|
|
||||||
n: 7
|
|
||||||
}
|
|
||||||
r.f(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn use_stack() {
|
fn use_stack() {
|
||||||
x := 7.5
|
x := 7.5
|
||||||
y := 3.25
|
y := 3.25
|
||||||
@ -3897,6 +3887,19 @@ fn main() {
|
|||||||
use_stack() // to erase invalid stack contents
|
use_stack() // to erase invalid stack contents
|
||||||
println('r: $r')
|
println('r: $r')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut r RefStruct) g() {
|
||||||
|
s := &MyStruct{ // `s` explicitly refers to a heap object
|
||||||
|
n: 7
|
||||||
|
}
|
||||||
|
// change `&MyStruct` -> `MyStruct` above and `r.f(s)` -> `r.f(&s)` below
|
||||||
|
// to see data in stack segment being overwritten
|
||||||
|
r.f(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut r RefStruct) f(s &MyStruct) {
|
||||||
|
r.r = unsafe { s } // override compiler check
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here the compiler check is suppressed by the `unsafe` block. To make `s` be heap
|
Here the compiler check is suppressed by the `unsafe` block. To make `s` be heap
|
||||||
|
Loading…
Reference in New Issue
Block a user