2015-01-11 3 views
12

명백한 이유 때문에 FnMut을 복제 할 수 없습니다.클로저를 복제 할 수 있습니까?

그러나 Fn에는 변경할 수없는 범위가 있습니다. Fn의 '중복'을 만드는 방법이 있습니까?

&mut core::ops::Fn(logger::Level, &'a collections::string::String) + Send does not implement any method in scope named clone

아니면 어떻게 든처럼 주위 FN에 원시 포인터를 전달하는 것이 안전합니다 :

그 결과 복제하려고

let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>> 

기술적으로 위의 작품 만 보인다 아주 이상한.

#![feature(unboxed_closures)] 

use std::thread::Thread; 
use std::clone::Clone; 

struct WithCall { 
    fp:Box<Fn<(i8,i8), i8> + Send> 
} 

impl WithCall { 
    pub fn new(fp:Box<Fn<(i8,i8), i8> + Send>) -> WithCall { 
    return WithCall { 
     fp: fp 
    }; 
    } 

    pub fn run(&self, a:i8, b:i8) -> i8 { 
    return self.fp.call((a, b)); 
    } 
} 

unsafe impl Send for WithCall {} 

impl Clone for WithCall { 
    fn clone(&self) -> WithCall { 
    return WithCall { 
     fp: self.fp.clone() 
    }; 
    } 
} 

fn main() { 
    let adder = WithCall::new(Box::new(|&:a:i8, b:i8| -> i8 { 
    return a + b; 
    })); 
    println!("{}", adder.run(1, 2)); 

    let add_a = adder.clone(); 
    let add_b = adder.clone(); 
    Thread::scoped(move || { 
    println!("In remote thread: {}", add_a.run(10, 10)); 
    }); 
    Thread::scoped(move || { 
    println!("In remote thread: {}", add_b.run(10, 10)); 
    }); 
} 

예 :

는 HUMM는, 좋아, 여기에 내가 할 노력하고있어의 예입니다. boxed closure가있는 구조체를 가지고 있다면 구조체를 여러 작업에 전달해야합니다. 분명히 당신은 할 수 없습니다. ...하지만 당신이 Box<Fn<>>를 복제 할 수없고 당신이 &Fn<...>

놀이 틀 복제 할 수 없기 때문에 당신은 또한 그것을 복제 할 수 없습니다 폐쇄가 자신의 환경을 캡처 기억 http://is.gd/1oNPYJ

+0

는 당신이 복제 된 폐쇄와 함께 할 싶은 구조체에 Fp 주위 Arc를 추가 받았죠? – Shepmaster

+0

전체 코드는 무엇입니까? – huon

+0

@shepmaster 특히 변경 가능한 상태가 아닌 클로저를 동시에 여러 작업으로 옮기고 싶습니다. 첨부 된 예를 참조하십시오. – Doug

답변

1

을, 그래서 그들은이 환경에 따라 자신의 평생 동안. 그러나 Fn*에 대한 참조를 취할 수 있으며, 주위에 더 사람들에 합격하거나, 구조체에 저장 :

fn do_more<F>(f: &F) -> u8 
    where F: Fn(u8) -> u8 
{ 
    f(0) 
} 

fn do_things<F>(f: F) -> u8 
    where F: Fn(u8) -> u8 
{ 
    // We can pass the reference to our closure around, 
    // effectively allowing us to use it multiple times. 
    f(do_more(&f)) 
} 

fn main() { 
    let val = 2; 
    // The closure captures `val`, so it cannot live beyond that. 
    println!("{:?}", do_things(|x| (x + 1) * val)); 
} 

내가 그것을 원시 포인터에 Fn* 변환 할 보편적으로 안전하지 말 주변을 통과 할 것 일생 동안의 걱정 때문에

11

당신이하려는 것은 여러 스레드에서 클로저를 호출하는 것입니다. 즉, 여러 스레드에서 클로저를 공유합니다. "여러 스레드에 걸쳐 공유"라는 문구가 마음에들 자마자 나의 첫 번째 생각은 to reach for Arc입니다 (적어도 RFC 458이 어떤 형태로 구현 될 때까지 &이 스레드에서 사용 가능할 때까지). 이렇게하면 안전한 공유 메모리가 허용됩니다 (Clone은 내부 형식이 Clone 일 필요없이 Clone이 동일한 메모리에 대한 새 포인터를 만들기 만 함). 따라서 하나의 Fn 개체를 여러 스레드에서 사용할 수 있으므로 필요가 없습니다 그것을 복제하십시오.

요약하면 을 Arc에 넣고 복제하십시오.

#![allow(unstable)] 

use std::thread::Thread; 
use std::sync::Arc; 

type Fp = Box<Fn(i8,i8) -> i8 + Send + Sync>; 

struct WithCall { 
    fp: Fp 
} 

impl WithCall { 
    pub fn new(fp: Fp) -> WithCall { 
     WithCall { fp: fp } 
    } 

    pub fn run(&self, a: i8, b: i8) -> i8 { 
     (*self.fp)(a, b) 
    } 
} 

fn main() { 
    let adder = WithCall::new(Box::new(|&: a: i8, b| a + b)); 
    println!("{}", adder.run(1, 2)); 

    let add_a = Arc::new(adder); 
    let add_b = add_a.clone(); 
    Thread::scoped(move || { 
     println!("In remote thread: {}", add_a.run(10, 10)); 
    }); 
    Thread::scoped(move || { 
     println!("In remote thread: {}", add_b.run(10, 10)); 
    }); 
} 

playpen

참고 : 나는 (.call를 사용하지 않는) 유형과 직접 () 통화에 대한 권장 설탕 Fn(...) -> ...를 사용하여 unboxed_closures 기능 게이트를 제거했습니다. 또한 내용이있는 경우 Send이 자동으로 구현되므로 불필요한 unsafe impl Send을 제거했습니다. unsafe impl은 내용이 기본값으로 Send이 아니고 프로그래머가 컴파일러의 보수적 인 판단을 무시하려는 경우에만 필요합니다.


올드 대답 (이 여전히 관련) : Fn::call&self을 소요하기 때문에 그것은하는 &mut Fn 특성 객체를 가지고 매우 이례적인 일이다. mut은 필요하지 않으며 문자 그대로 제로 추가 기능을 추가한다고 생각합니다. &mut Box<Fn()>을 사용하면 일부 기능이 추가되지만 이는 드문 경우입니다.

&mut 대신 & 포인터로 변경하면 더 자연스럽게 작동합니다 (&Fn&Box<Fn> 모두). 당신이 사용하고있는 실제 코드를 보지 않고, 당신이 무슨 일을하는지 정확히 이야기하기가 매우 어렵지만,

fn call_it(f: &Fn()) { 
    (*f)(); 
    (*f)(); 
} 
fn use_closure(f: &Fn()) { 
    call_it(f); 
    call_it(f); 
} 

fn main() { 
    let x = 1i32; 
    use_closure(&|| println!("x is {}", x)); 
} 

(이 부분적으로 인해 &T가 부분적으로 역 차용으로도 Copy 이도록하고있다, 그것은 &mut와 함께 작동 .뿐만 아니라) 또는

, 당신은 종료 오버 할 수 가능성이 많은 상황에서 작동하는 폐쇄 :

fn foo(f: &Fn()) { 
    something_else(|| f()) 
} 

Obviously a FnMut cannot be cloned, for obvious reasons.

FnMut은 복제 할 수없는 고유 한 이유가 없습니다. 일부 필드가있는 구조체이며 FnFnOnce의 경우 각각 &self 또는 self이 아닌 을 취하는 메서드입니다. 구조체를 만들고 FnMut을 수동으로 구현하는 경우에도 Clone을 구현할 수 있습니다. 당신이 만족 녹의 앨리어싱과 수명 요구 사항을 보장하기 위해주의 인 경우

Or is it safe to somehow pass a raw pointer to a Fn around, like:

let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>> 

Technically the above works, but it seems quite weird.

은 기술적으로 그것을 작동 ...하지만 안전하지 않은 포인터에 탈퇴하여 컴파일러의 도움을 두지 않을 자신에 그 부담을 옮기고 당신. 컴파일러 오류에 대한 올바른 응답은 unsafe 코드를 사용하는 것이 상대적으로 드뭅니다. 오류를 조사하고 코드를 조정하여 컴파일러에서보다 의미가있게 만드는 경우는 드뭅니다.). 여기

+0

죄송합니다. 그건 약간의 쓰레기 문제였습니다. 나는 그것을하려고하는 것에 대한 예를 들어 업데이트했다. 클로저를 닫는 것은 해결책 일지 모르지만 어떻게 할지는 모르겠습니다. – Doug

+0

@Doug, 예, 실제 출처가없는 질문은 유용한 방식으로 대답하기가 극히 어렵습니다. 업데이트 됨. – huon

0

는 의도가이 일을하는 것입니다 1.22.1

의 작업 코드입니다.

let x = |x| { println!("----{}",x)}; 

let mut y = Box::new(x); 

y.clone(); 

상단에 제안 된 원본 코드가 사용되었습니다.

클로저를 Fn 클로닝부터 시작했다.

type Fp = Box<Fn(i8, i8) -> i8 + Send + Sync>; 

WithCall

Play rust : working code Gist : working code in 1.22.1

관련 문제