2017-12-12 2 views
0

녹에 다음 코드가 있습니다. 지역 변수에 대한 참조를 반환하지 않아도된다는 것을 알고 있으며,이 경우에는 그렇지 않습니다. 분할 할 문자열은 &str 참조로 전달되며 분할 경계를 결정한 후 &s[0..idx]을 반환합니다. 여기서 idx은 경계의 끝입니다. 나는 이것이 "dangling"참조 관련 오류를 발생시키지 않을 것이라고 확신했다. 그러나 그것은 내가 틀렸다는 것이 드러났습니다! 모든 설명이 크게 감사합니다누락 된 수명 연산자

error[E0106]: missing lifetime specifier 
--> src/main.rs:7:37 
    | 
7 | fn str_split(s: &str, pat: &str) -> &str { 
    |         ^expected lifetime parameter 
    | 
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `s` or `pat` 

:

fn demo4() { 
    let mut s = String::from("Elijah Wood"); 
    let firstname = str_split(&s, &String::from(" ")); 
    println!("First name of actor: {}", firstname); 
} 
// can handle both &str and &String 
fn str_split(s: &str, pat: &str) -> &str { 
    let bytes = s.as_bytes(); 
    let b_pat = pat.as_bytes(); 
    for (i, &item) in bytes.iter().enumerate() { 
     if item == b_pat { 
      return &s[0..i]; 
     } 
    } 
    &s[..] 
} 

fn main() { 
    demo4(); 
} 

나는 다음과 같은 오류를 얻고있다.

+0

@trentcl 스냅 샷이 당신을 괴롭히는 경우 사과드립니다. 그때는 가장 좋은 생각 같았습니다 –

+0

오류 메시지는 잠재적 인 응답자뿐만 아니라 미래의 질문자에게도 똑같은 질문을하는 텍스트로 사용하는 것이 좋습니다. 별로 중요하지 않습니다. – trentcl

+0

@trentcl 귀하의 요지가 있습니다. 모든 포인터 왜 컴파일러 오류에 관한? –

답변

3

&str'a 미리 선언 할 필요가 일부 수명 매개 변수입니다 &'a str위한 속기 :이 순수하게 학습 운동이 아니라면 당신이 것보다 더 많은 일을하지 않습니다. 몇 가지 간단한 경우. 이 평생 매개 변수를 생략 할 수 있으며 컴파일러가 확장합니다. 그러나 명시 적으로 수명을 선언해야하는 경우가 있습니다.

The Rust Programming Language, Second Edition (강조 광산)에서 생략 수명 매개 변수에 대한 규칙은 다음과 같습니다

  1. Each parameter that is a reference gets its own lifetime parameter. In other words, a function with one parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32) , a function with two arguments gets two separate lifetime parameters: fn foo<'a, 'b>(x: &'a i32, y: &'b i32) , and so on.

  2. If there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32 .

  3. If there are multiple input lifetime parameters, but one of them is &self or &mut self because this is a method, then the lifetime of self is assigned to all output lifetime parameters. This makes writing methods much nicer.

함수의 문제는 따라서 컴파일러는 당신을 위해 하나를 선택하지 않을 것이다, 두 개의 입력 평생 매개 변수를 가지고 있다는 것입니다 .이 같은 함수를 작성해야 :이 구문은 당신에게 새로운

fn str_split<'a>(s: &'a str, pat: &str) -> &'a str { 
    s 
} 

경우 the chapter on lifetimes을 읽을 수 있는지 확인하십시오.

컴파일러가 왜 그걸 알아낼 수 없습니까? Rust는 함수의 구현이 변경 되었기 때문에 함수의 시그니처가 변경되어서는 안된다는 원칙을 가지고 있기 때문입니다. 컴파일러를 간소화하고 (서명이 완전히 결정되지 않은 상호 의존 함수를 처리 할 필요가 없으며) 자체 코드의 유지 관리를 단순화합니다. 예를 들어,라면과 같이 함수의 구현을 변경하려면 다음

fn str_split(s: &str, pat: &str) -> &str { 
    pat 
} 

다음 출력의 수명 매개 변수가 pat의 수명 매개 변수에 연결되어야한다. 도서관에서 이것은 큰 변화입니다. 당신은 깨닫지 않고 변경 사항을 깨는 것을 원하지 않습니다!

+0

설명해 주셔서 감사합니다. 많은 도움이되었습니다. –

2

오류 메시지가 그것을 해결하기 위해 어떻게하지 않지만, 무엇이 잘못되었는지를 알려줍니다 :

= help: this function's return type contains a borrowed value, but the 
signature does not say whether it is borrowed from `s` or `pat` 

컴파일러는 코드가 안전 여부를 확인하기 위해 수명을 사용합니다. 그 중 일부는 각 참조가 파생 된 위치를 아는 것입니다. 서명 : 녹는 기준의 유효성을 검사하는 방법을 말할 수

fn str_split(s: &str, pat: &str) -> &str 

, 그것은 s로 참조 또는 pat에 대한 참조를 반환 여부를 표시하지 않습니다. (함수가 전혀 참조 인수가없는이의 버전도 this question를 참조하십시오.)

는이 문제를 해결하려면, 당신은 일반적인 수명 매개 변수 소개합니다 :이 말한다

fn str_split<'a>(s: &'a str, pat: &str) -> &'a str 

을 대략 "평생 문자열 인 'a의 경우 str_split과 다른 문자열을 입력하여 평생 'a이라는 참조를 다시받을 수 있습니다." &pat의 수명은 결과에 연결되지 않으므로 'a으로 주석 처리되지 않았습니다.

이 매우 문제를 해결하는 녹 프로그래밍 언어 has a chapter on lifetimes 및 나는 그것을 읽는 것이 좋습니다. 녹의 수명은 단순히 매달려있는 포인터를 막는 것 이상의 것입니다.


마지막으로 질문의 일부는 아니지만이 기능의 본문은 한 줄짜리 코드입니다.

fn str_split<'a>(s: &'a str, pat: &str) -> &'a str { 
    s.split(pat).next().unwrap_or(s) 
} 
0

누구나 오류 및 그 이유를 설명해 주셔서 감사합니다. 나는 코드를 수정하고 설명 할 부분을 약간 변경했다. 패턴 매칭이 의미 상으로 잘못되었다는 점에 대해 @trentcl에게 먼저 감사드립니다. 그 패턴에 대한 검색은 전체 배열 자체가 아닌 배열의 각 바이트에 대해 일치시킴으로써 수행되었습니다. 이것은 공백 문자 ' '의 첫 번째 발생을 나누어 단어를 반환하는 기능을 변경하게되었습니다. 또한 함수 시그니처에는 올바르게 컴파일되도록 수명 특성이 필요했습니다. 작업 코드는 아래와 같습니다 :

// 4 Demo with string spliting 
fn demo4() { 
    let s = String::from("Elijah Wood"); 
    let firstname = str_split(&s); 
    println!("First name of actor: {}", firstname); 
} 
// splits a string at first space 
fn str_split<'a>(s : &'a str) -> &'a str { 
    let bytes = s.as_bytes(); 
    for(i, &item) in bytes.iter().enumerate() { 
     if item == b' ' { 
      return &s[0..i]; 
     } 
    } 
    &s[..] 
} 
+1

['split'] (https://doc.rust-lang.org/std/primitive.str.html#method.split) 또는 ['split_whitespace'] (https : //doc.rust-lang.org/std/primitive.str.html#method.split_whitespace) (필자는'split' 기반 버전으로 내 대답을 업데이트했습니다.) 그렇더라도 문자열을 바이트로 표시합니다. [예] (https://play.rust-lang.org/?gist=ee555511c1034da0182ea0b5df194cf7&version=stable) – trentcl

관련 문제